-
Move to ESP8266
10/20/2020 at 20:14 • 0 commentsLights and Pump
Nothing fancy here. The ESP is 3.3V logic and I had some issue using 5V relais, npn transistors and the digital outputs of the nodemcu. Probably my (lack of) soldering skillz are the issue but sometimes the connections were working, sometimes not. Next best thing: using two solid state relais, as you can see on the figure below.
Software controlling the lamp and the pump is nothing fancy. The lamp is on for 9 hours and then off for 15. The pump is on for 10 minutes and off for 4 hours. No pump when the light is off. Since the ESP has not Real Time Clock, the micros() function is used and each minute I update a parameter to keep track of the time pased during each cycle.
Web interface
Wanting to be able to update the settings of the pump and the light remotely, and the reason why I am trying the ESP is for finding out what the Wifi module can do.
The easiest way I found was using the ESP8266WebServer and the GET method. Programming the Web-page, of which the first version looks like this:Getting the information afterward is then easy, checking the content of the parameters attached to the html forms.
if (server.arg("newLightOn") != "") { String ipt1 = server.arg("newLightOn"); LightCycle_on = ipt1.toInt(); LightCycletime = (((LightStatus + 1) % 2) * LightCycle_off) + (((LightStatus) % 2) * LightCycle_on); }
The one thing I don't like the way the html page is built, writing it as one long string, which is not really clear and cumbersome to add css styling.
Coming up next
As you might already see in the first image I connected a BME sensor as well, and in the future I want to monitor the temperature and moister, so that I can update pump and light timings for instance.
Remarks
When resetting the ESP module I need to decouple one of the digital outputs for it to boot up correctly. Uh, if you have any idea why, please let me know.
Not convinced about my settings for the Wifi. I am only able to connect to the module when I am close, and even then it is not consistent. Even though I want the ESP to connect to the avaiable Wifi another hotspot is still created that I can sometimes more easily connect to "esp8266". Could this be something lingering in the flash from a previous build?
The code
Below the full code of the project so far, feel free reach out if you have comments or remarks:
#include <ESP8266WiFi.h> #include <WiFiClient.h> #include <ESP8266WiFiMulti.h> #include <ESP8266mDNS.h> #include <ESP8266WebServer.h> ESP8266WiFiMulti wifiMulti; // Create an instance of the ESP8266WiFiMulti class, called 'wifiMulti' ESP8266WebServer server(80); // Create a webserver object that listens for HTTP request on port 80 void handleRoot(); // Function for HTTP handlers void handleNotFound(); // Function for HTTP handlers // Parameters for UV light controls int LightOutputPin = 0; // Pin on the ESP controlling the light int LightManual = 0; // Manually control state of the light int LightStatus = 0; // Current status of the light int LightCycle_on = 8 * 60; // Minutes. int LightCycle_off = 16 * 60; // Minutes. int LightCycletime = LightCycle_off; // Cycle to start with int Light_minutes = 0; // Timer to keep track of the current cycle // Parameters for the nutrient pump int PumpOutputPin = 14; // Pin on the ESP controlling the pump int PumpManual = 0; // manually control state of the light int PumpStatus = 0; // Current status of the pump int PumpCycle_on = 10; // Minutes. int PumpCycle_off = 5 * 60; // Minutes. int PumpCycletime = PumpCycle_off; // Cycle to start with int Pump_minutes = 0; // Timer to keep track of the current cycle // Manual control active yes or no? int manualCtrl_active = 0; // timer for the micros() to keep track of the minutes unsigned long timer; // Visualizations for the site String ControlType[2] = {"automatic", "manual"}; String activeState[2] = {"OFF", "ON"}; void setup(void) { // Setting the initial states of the digital outputs pinMode(LightOutputPin, OUTPUT); pinMode(PumpOutputPin, OUTPUT); digitalWrite(LightOutputPin, LightStatus); digitalWrite(PumpOutputPin, PumpStatus); Serial.begin(9600); // Start the Serial communication to send messages to the computer delay(10); Serial.println(' '); // Settings if you want an access point for the ESP instead of connecting to your Wifi //WiFi.softAP("ssid", "password"); // we want its own wifi network not connect to existing //IPAddress myIP = WiFi.softAPIP(); //Serial.print("AP IP address:"); //Serial.println(myIP); // Send the IP address of the ESP8266 to the computer // Settings if you want the ESP to connect with existing WIFI network wifiMulti.addAP("SSID", "Password"); // add Wi-Fi networks you want to connect to Serial.println("Connecting ..."); int i = 0; // Wait for the Wi-Fi to connect: scan for Wi-Fi networks, and connect to the strongest of the networks above while (wifiMulti.run() != WL_CONNECTED) { delay(250); Serial.print('.'); } Serial.println(' '); Serial.print("Connected to "); Serial.println(WiFi.SSID()); // Tell us what network we're connected to Serial.print("IP address: "); Serial.println(WiFi.localIP()); // Send the IP address of the ESP8266 to the computer if (MDNS.begin("esp8266")) { // Start the mDNS responder for esp8266.local (not sure what) Serial.println("mDNS responder started"); } else { Serial.println("Error setting up MDNS responder!"); } server.on("/", HTTP_GET, handleRoot); // Call the 'handleRoot' function when a client requests URI "/" server.onNotFound(handleNotFound); // When a client requests an unknown URI (i.e. something other than "/"), call function "handleNotFound" server.begin(); // Actually start the server Serial.println("HTTP server started"); } void loop(void) { if ((micros() - timer) >= 60 * 1000000) { // ESP has no RTC and micro's only lasts ~70 minutes Pump_minutes = Pump_minutes + 1; // Light_minutes = Light_minutes + 1; // timer = micros(); } server.handleClient(); // Listen for HTTP requests from clients setLightStatus(); // Determine the status of the UV light setPumpStatus(); // Determine the status of the nutrient pump } void handleRoot() { // When URI / is requested, capture the inputs and send the webpage // Capture any available inputs if (server.arg("newLightOn") != "") { String ipt1 = server.arg("newLightOn"); LightCycle_on = ipt1.toInt(); LightCycletime = (((LightStatus + 1) % 2) * LightCycle_off) + (((LightStatus) % 2) * LightCycle_on); } if (server.arg("newLightOff") != "") { String ipt2 = server.arg("newLightOff"); LightCycle_off = ipt2.toInt(); LightCycletime = (((LightStatus + 1) % 2) * LightCycle_off) + (((LightStatus) % 2) * LightCycle_on); //Serial.println(String(LightCycle_off)); } if (server.arg("newPumpOn") != "") { String ipt3 = server.arg("newPumpOn"); PumpCycle_on = ipt3.toInt(); PumpCycletime = (((PumpStatus + 1) % 2) * PumpCycle_off) + (((PumpStatus) % 2) * PumpCycle_on); //Serial.println(String(PumpCycle_on)); } if (server.arg("newPumpOff") != "") { String ipt4 = server.arg("newPumpOff"); PumpCycle_off = ipt4.toInt(); PumpCycletime = (((PumpStatus + 1) % 2) * PumpCycle_off) + (((PumpStatus) % 2) * PumpCycle_on); //Serial.println(String(PumpCycle_off)); } if (server.arg("HydroponicCtrl") != "") { if (server.arg("HydroponicCtrl") == "manual") { manualCtrl_active = 1; String ipt5 = server.arg("LightSetMan"); LightManual = ipt5.toInt(); String ipt6 = server.arg("PumpSetMan"); PumpManual = ipt6.toInt(); //Serial.println(String(LightManual)); } else { timer = micros(); manualCtrl_active = 0; Pump_minutes = 0; Light_minutes = 0; LightCycletime = (((LightStatus +1) % 2) * LightCycle_off) + (((LightStatus) % 2) * LightCycle_on); PumpCycletime = (((PumpStatus +1) % 2) * PumpCycle_off) + (((PumpStatus) % 2) * PumpCycle_on); } } setLightStatus(); // Determine the status of the UV light setPumpStatus(); // Determine the status of the nutrient pump // Visualize the web page: server.send(200, "text/html", "<div style="width: 50%; border:solid;"><h1>Hydroponic control settings</h1> <h2>Manual control settings</h2> <form action="/" method="GET"><label for="lightCtrl">Manually control the outputs?</label></br> <select name="HydroponicCtrl" id="HydroponicCtrl"> <option value="manual">Manual Control</option> <option value="automatic">Automatic Control</option></select></br> <select name="LightSetMan" id="LightSetMan"> <option value="1">Light ON</option> <option value="0">Light OFF</option></select> <select name="PumpSetMan" id="PumpSetMan"> <option value="1">Pump ON</option> <option value="0">Pump OFF</option></select></br> <input type="submit" value="Submit"> </select></form> <h2>Light control settings</h2> <form action="/" method="GET"> Light on time [min]: (currently: " + String(float(LightCycle_on) / 60) + " h)</br><input type="number" name="newLightOn"></br> Light off time [min]: (currently: " + String(float(LightCycle_off) / 60) + " h)</br><input type="number" name="newLightOff"></br><input type="submit" value="Submit"></form> <h2>Pump control settings</h2> <form action="/" method="GET"> Pump on time [min]: (currently: " + String(float(PumpCycle_on) / 60) + " h)</br><input type="number" name="newPumpOn"></br> Pump off time [min]: (currently: " + String(float(PumpCycle_off) / 60) + " h)</br><input type="number" name="newPumpOff"></br><input type="submit" value="Submit"></form></div> <div style="width: 50%; border:solid;"><h1>Hydroponic control states</h1><table style="width:60%; border:solid;"> <tr><td>Controller type:</td><td>"+ ControlType[manualCtrl_active] +"</td></tr> <tr><td>Light Status:</td><td>"+activeState[LightStatus]+"</td></tr> <tr><td>Cycletime remaining:</td><td>"+(LightCycletime - Light_minutes)+" min</td></tr> <tr><td>Pump Status:</td><td>"+activeState[PumpStatus]+"</td></tr> <tr><td>Cycletime remaining:</td><td>"+(PumpCycletime - Pump_minutes)+" min</td></tr> </table></div>"); } void handleNotFound() { server.send(404, "text/plain", "404: Not found"); // Send HTTP status 404 (Not Found) when there's no handler for the URI in the request } void setLightStatus() { // Determine and set the status of the Light if (manualCtrl_active == 1) { digitalWrite(LightOutputPin, LightManual); LightStatus = LightManual; }else { if ((Light_minutes) >= (LightCycletime)) { LightStatus = (LightStatus + 1) % 2; digitalWrite(LightOutputPin, LightStatus); Light_minutes = 0; LightCycletime = (((LightStatus + 1) % 2) * LightCycle_off) + (((LightStatus) % 2) * LightCycle_on); //Serial.println(String(Light_minutes)); } } } void setPumpStatus() { // Determine and set the status of the pump if (manualCtrl_active == 1) { digitalWrite(PumpOutputPin, PumpManual); PumpStatus = PumpManual; }else if(LightStatus == 0){ // no pump when the lights are out digitalWrite(PumpOutputPin, 0); PumpStatus = 0; }else{ if ((Pump_minutes) >= (PumpCycletime)) { PumpStatus = (PumpStatus + 1) % 2; digitalWrite(PumpOutputPin, PumpStatus); Pump_minutes = 0; PumpCycletime = (((PumpStatus + 1) % 2) * PumpCycle_off) + (((PumpStatus) % 2) * PumpCycle_on); //Serial.println(String(Pump_minutes)); } } }
-
Setting up a set-up
10/20/2020 at 20:11 • 0 commentsParts parts parts
Starting things simple I wanted to try the concept and get a feel for the feasibility. This setup consists of one T-junction of 10mm diameter plastic piping, normally used for plumbing.
Holding the plant (cauliflower) is a 3D printed part, partly filled with perlite. The plant itself is seeted in a little bit of earth. I first tried to germinate the seeds in continuously moist earth, in the setup, but that was not a success. Germinating in a little more dry earth worked much better.The figure below shows the small setup I have right now (yes I did say I wasn't going to use an Arduino, but I am still waiting on my nodemcu V2 esp8266 board). The lamp is a 25 W UV light used for terrariums and has the right spectral properties for growing plants (In the future I might move to LED's though). Everything is placed on a plastic container that holds the nutrient.
Not the intended ebb and flow method either. The valve I bought needs a delta pressure of 0.8 bars so nothing dripped trough on this very small usecase. So now, the pump is activated every thirty minutes for 5 seconds. When moving to the esp module I want to be able to remotely change the timings for both the pump and the light. More on that next time.
'Hydraulics'
As mentioned before, the part I used has been 3D printed. The part has been printed in two pieces (so it is 2 parts?) in PLA. Not the ideal material, but it is what was available, we'll see how long it lasts.
I started out with a 6 V pump, which could then easily be actuated from the same supply as the controller. In the top of the plant holder I placed a ring of tubing with holes to evenly distribute the nutrient arount the plant base.
However, the holes were too small, or not enough of them, causing too much resistance of the pump and after three days I had to say goodbye.
With my sights set on the future, I removed the ring, and replaced the pump with a more powerfull aquarium pump. This seems to be a better fit and should be able to stay with me when upgrading to a bigger 'farm'.
-
Project introduction
10/20/2020 at 20:11 • 0 commentsIntro
Groing plants hydroponically is basically without using soil. The roots of the plants are being exposed to a nutrient, which is a water based fluid that contains all the food the plant is going to need.
The benefit is that this way plants can be grown in more severe environents and even indoors. Another benfit is a drastic decrease in the amount of water needed for cultivating a plant and 'faster' groing times, since the plant does not need to invest as much energy to cultivating the root system.There are a lot of different types of hydroponic farming, and the type that speaks to me the most is the ebb and flood type. A crude sketch of what I am imagining:
What I think I need
- 10 cm tube: To keep the plants and pass through the nutrient. The plan is to start with a single T-junction to use as a setup for my proof of concept.
- pump: To flush the nutrient through the tube.
- Hose tail: One or two to drain and fill the pipe with nutrient.
- Hoses: To connect everything.
- UV light: Shall provide natural light, in case I want to grow the plants in my basement or winter times.
- Controller: For controlling the pump, valve and the light cycle. Looking forward to try something else than an Arduino, I'll opt to use an ESP8266 controller board.
- Relais: 1-3 pending on the type of pump, valve and lights.
- Net cup: for growing the medium in, still thinking about what would be the better medium.
- Ph tester: For optimal intake of nutrients, the fluid should have a Ph between 5.5 and 6.5.
- Vent: To provide a breeze, removing the moisture from the leaves to avoid fungi. Thinking about it, this shall only be a lesser priority.