Smart Greenhouse Project with PicoBricks
PicoBricks is a versatile robotic platform powered by the Raspberry Pi Pico microcontroller. This platform enables users to build an array of robotic projects by interconnecting various sensors, motors, and other components.
Here are some of the robotic projects that can be created with PicoBricks:
The PicoBricks platform offers a wide range of possibilities for creating various robotic projects. For instance, you can design an automatic irrigation system that uses moisture sensors to measure soil moisture and install a motorized irrigation system to water the plants.
Additionally, PicoBricks can be used to create an autonomous car that uses ultrasonic sensors to detect obstacles and a motor driver to control the car's motors. Another application is a line following robot that moves by following a line on a surface, which can be achieved with the help of PicoBricks.
The platform's PWM signal generation capability can also be used to control the movements of a robotic arm, making it an ideal solution for building a controlled robotic arm.
Moreover, PicoBricks can be used for educational purposes, allowing students to learn STEM subjects and develop their engineering and programming skills by creating their robotic projects.

Creating an automatic irrigation system with PicoBricks is quite easy. Here is a step-by-step guide on how to do it:
Materials:
Raspberry Pi Pico
Soil moisture sensor
DC motor
Watering hose
Breadboard
Jumper cables
Power supply
Transistor
Step 1: Connect the soil moisture sensor
Connect the soil moisture sensor to the breadboard. Connect the VCC pin of the sensor to the 3V3 pin of the Pico, the GND pin to the GND pin of the Pico, and the AO pin to the A0 pin of the Pico.
Step 2: Connect the DC motor
Connect the DC motor to the breadboard. Connect the positive connection of the motor to the Vin pin of the Pico and the negative connection to the emitter of a transistor. Connect the collector of the transistor to the GND pin of the Pico and connect the base of the transistor to a GPIO pin. This GPIO pin will be used to generate the PWM signals to control the motor.
Step 3: Connect the watering hose
Connect the watering hose to the output of the motor.
Step 4: Write the code
Using the Python programming language, write a code to read the data from the soil moisture sensor and turn the motor on and off based on this data. In the code, you will also generate PWM signals to adjust the speed of the motor.

Example cods belows: MicroPython
import utime
import uos
import machine
from machine import Pin, ADC
from picobricks import DHT11
from utime import sleep
dht_sensor = DHT11(Pin(11))
smo_sensor=ADC(27)
m1 = Pin(22, Pin.OUT)
m1.low()
print("Machine: \t" + uos.uname()[4])
print("MicroPython: \t" + uos.uname()[3])
uart0 = machine.UART(0, baudrate=115200)
print(uart0)
def Connect_WiFi(cmd, uart=uart0, timeout=5000):
print("CMD: " + cmd)
uart.write(cmd)
utime.sleep(7.0)
Wait_ESP_Rsp(uart, timeout)
print()
def Rx_ESP_Data():
recv=bytes()
while uart0.any()>0:
recv+=uart0.read(1)
res=recv.decode('utf-8')
return res
def Send_AT_Cmd(cmd, uart=uart0, timeout=2000):
print("CMD: " + cmd)
uart.write(cmd)
Wait_ESP_Rsp(uart, timeout)
print()
def Wait_ESP_Rsp(uart=uart0, timeout=2000):
prvMills = utime.ticks_ms()
resp = b""
while (utime.ticks_ms()-prvMills)<timeout:
if uart.any():
resp = b"".join([resp, uart.read(1)])
print("resp:")
try:
print(resp.decode())
except UnicodeError:
print(resp)
Send_AT_Cmd('AT\r\n') #Test AT startup
Send_AT_Cmd('AT+GMR\r\n') #Check version information
Send_AT_Cmd('AT+CIPSERVER=0\r\n')
Send_AT_Cmd('AT+RST\r\n') #Check version information
Send_AT_Cmd('AT+RESTORE\r\n') #Restore Factory Default Settings
Send_AT_Cmd('AT+CWMODE?\r\n') #Query the WiFi mode
Send_AT_Cmd('AT+CWMODE=1\r\n') #Set the WiFi mode = Station mode
Send_AT_Cmd('AT+CWMODE?\r\n') #Query the WiFi mode again
Send_AT_Cmd('AT+CWJAP="ID","Password"\r\n', timeout=5000) #Connect to AP
utime.sleep(3.0)
Send_AT_Cmd('AT+CIFSR\r\n') #Obtain the Local IP Address
utime.sleep(3.0)
Send_AT_Cmd('AT+CIPMUX=1\r\n')
utime.sleep(1.0)
Send_AT_Cmd('AT+CIPSERVER=1,80\r\n') #Obtain the Local IP Address
utime.sleep(1.0)
while True:
res =""
res=Rx_ESP_Data()
utime.sleep(2.0)
if '+IPD' in res: # if the buffer contains IPD(a connection), then respond with HTML handshake
id_index = res.find('+IPD')
if '/WATERING' in res:
print('Irrigation Start')
m1.high()
utime.sleep(10)
m1.low()
print('Irrigation Finished')
connection_id = res[id_index+5]
print("connectionId:" + connection_id)
print ('! Incoming connection - sending webpage')
uart0.write('AT+CIPSEND='+connection_id+',200'+'\r\n')
utime.sleep(1.0)
uart0.write('HTTP/1.1 200 OK'+'\r\n')
uart0.write('Content-Type: text/html'+'\r\n')
uart0.write('Connection: close'+'\r\n')
uart0.write(''+'\r\n')
uart0.write('<!DOCTYPE HTML>'+'\r\n')
uart0.write('<html>'+'\r\n')
uart0.write('<body><center><H1>CONNECTED...<br/></H1></center>'+'\r\n')
uart0.write('<body><center><H1>Irrigation Complete.<br/></H1></center>'+'\r\n')
uart0.write('<script>class RocketElementorAnimation{constructor(){this.deviceMode=document.createElement("span"),this.deviceMode.id="elementor-device-mode",this.deviceMode.setAttribute("class","elementor-screen-only"),document.body.appendChild(this.deviceMode)}_detectAnimations(){let t=getComputedStyle(this.deviceMode,":after").content.replace(/"/g,"");this.animationSettingKeys=this._listAnimationSettingsKeys(t),document.querySelectorAll(".elementor-invisible[data-settings]").forEach(t=>{const e=t.getBoundingClientRect();if(e.bottom>=0&&e.top<=window.innerHeight)try{this._animateElement(t)}catch(t){}})}_animateElement(t){const e=JSON.parse(t.dataset.settings),i=e._animation_delay||e.animation_delay||0,n=e[this.animationSettingKeys.find(t=>e[t])];if("none"===n)return void t.classList.remove("elementor-invisible");t.classList.remove(n),this.currentAnimation&&t.classList.remove(this.currentAnimation),this.currentAnimation=n;let s=setTimeout(()=>{t.classList.remove("elementor-invisible"),t.classList.add("animated",n),this._removeAnimationSettings(t,e)},i);window.addEventListener("rocket-startLoading",function(){clearTimeout(s)})}_listAnimationSettingsKeys(t="mobile"){const e=[""];switch(t){case"mobile":e.unshift("_mobile");case"tablet":e.unshift("_tablet");case"desktop":e.unshift("_desktop")}const i=[];return["animation","_animation"].forEach(t=>{e.forEach(e=>{i.push(t+e)})}),i}_removeAnimationSettings(t,e){this._listAnimationSettingsKeys().forEach(t=>delete e[t]),t.dataset.settings=JSON.stringify(e)}static run(){const t=new RocketElementorAnimation;requestAnimationFrame(t._detectAnimations.bind(t))}}document.addEventListener("DOMContentLoaded",RocketElementorAnimation.run);</script></body></html>'+'\r\n')
elif '/SERA' in res:
#sleep(1) # It was used for DHT11 to measure.
dht_sensor.measure() # Use the sleep() command before this line.
temp=dht_sensor.temperature
hum=dht_sensor.humidity
smo=round((smo_sensor.read_u16()/65535)*100)
sendStr="\"TEMP\":{}, \"Humidity\":{}, \"S.Moisture\":{}%".format(temp,hum,smo)
sendText="{"+sendStr+"}"
strLen=46+len(sendText)
connection_id = res[id_index+5]
print("connectionId:" + connection_id)
print ('! Incoming connection - sending webpage')
atCmd="AT+CIPSEND="+connection_id+","+str(strLen)
uart0.write(atCmd+'\r\n')
utime.sleep(1.0)
uart0.write('HTTP/1.1 200 OK'+'\r\n')
uart0.write('Content-Type: text/html'+'\r\n')
uart0.write(''+'\r\n')
uart0.write(sendText+'\r\n')
elif '/' in res:
print("resp:")
print(res)
connection_id = res[id_index+5]
print("connectionId:" + connection_id)
print ('! Incoming connection - sending webpage')
uart0.write('AT+CIPSEND='+connection_id+',200'+'\r\n')
utime.sleep(3.0)
uart0.write('HTTP/1.1 200 OK'+'\r\n')
uart0.write('Content-Type: text/html'+'\r\n')
uart0.write('Connection: close'+'\r\n')
uart0.write(''+'\r\n')
uart0.write('<!DOCTYPE HTML>'+'\r\n')
uart0.write('<html>'+'\r\n')
uart0.write('<body><center><H1>CONNECTED.<br/></H1></center>'+'\r\n')
uart0.write('<center><h4>INFO:Get Sensor Data</br>WATERING:Run Water Pump</h4></center>'+'\r\n')
uart0.write('</body></html>'+'\r\n')
utime.sleep(4.0)
Send_AT_Cmd('AT+CIPCLOSE='+ connection_id+'\r\n') # once file sent, close connection
utime.sleep(3.0)
recv_buf="" #reset buffer
print ('Waiting For connection...')
Arduino C Codes
#include <DHT.h>
#define RX 0
#define TX 1
#define LIMIT_TEMPERATURE 30
#define DHTPIN 11
#define DHTTYPE DHT11
#define smo_sensor 27
#define motor 22
#define DEBUG true
DHT dht(DHTPIN, DHTTYPE);
int connectionId;
void setup() {
Serial1.begin(115200);
dht.begin();
pinMode(smo_sensor, INPUT);
pinMode(motor, OUTPUT);
sendData("AT+RST\r\n", 2000, DEBUG); // reset module
sendData("AT+GMR\r\n", 1000, DEBUG); // configure as access point
sendData("AT+CIPSERVER=0\r\n", 1000, DEBUG); // configure as access point
sendData("AT+RST\r\n", 1000, DEBUG); // configure as access point
sendData("AT+RESTORE\r\n", 1000, DEBUG); // configure as access point
sendData("AT+CWMODE?\r\n", 1000, DEBUG); // configure as access point
sendData("AT+CWMODE=1\r\n", 1000, DEBUG); // configure as access point
sendData("AT+CWMODE?\r\n", 1000, DEBUG); // configure as access point
sendData("AT+CWJAP=\"WIFI_ID\",\"WIFI_PASSWORD\"\r\n", 5000, DEBUG); // ADD YOUR OWN WIFI ID AND PASSWORD
delay(3000);
sendData("AT+CIFSR\r\n", 1000, DEBUG); // get ip address
delay(3000);
sendData("AT+CIPMUX=1\r\n", 1000, DEBUG); // configure for multiple connections
delay(1000);
sendData("AT+CIPSERVER=1,80\r\n", 1000, DEBUG); // turn on server on port 80
delay(1000);
}
void loop() {
if (Serial1.find("+IPD,")) {
delay(300);
connectionId = Serial1.read() - 48;
String serialIncoming = Serial1.readStringUntil('\r');
Serial.print("SERIAL_INCOMING:");
Serial.println(serialIncoming);
if (serialIncoming.indexOf("/WATERING") > 0) {
Serial.println("Irrigation Start");
digitalWrite(motor, HIGH);
delay(1000); // 10 sec.
digitalWrite(motor, LOW);
Serial.println("Irrigation Finished");
Serial.println("! Incoming connection - sending WATERING webpage");
String html = "";
html += "<html>";
html += "<body><center><H1>Irrigation Complete.<br/></H1></center>";
html += "</body></html>";
espsend(html);
}
if (serialIncoming.indexOf("/SERA") > 0) {
delay(300);
float smo = analogRead(smo_sensor);
float smopercent = (460-smo)*100.0/115.0 ; //min ve max değerleri değişken.
Serial.print("SMO: %");
Serial.println(smo);
float temperature = dht.readTemperature();
Serial.print("Temp: ");
Serial.println(temperature);
float humidity = dht.readHumidity();
Serial.print("Hum: ");
Serial.println(humidity);
Serial.println("! Incoming connection - sending SERA webpage");
String html = "";
html += "<html>";
html += "<body><center><H1>TEMPERATURE<br/></H1></center>";
html += "<center><H2>";
html += (String)temperature;
html += " C<br/></H2></center>";
html += "<body><center><H1>HUMIDITY<br/></H1></center>";
html += "<center><H2>";
html += (String)humidity;
html += "%<br/></H2></center>";
html += "<body><center><H1>SMO<br/></H1></center>";
html += "<center><H2>";
html += (String)smopercent;
html += "%<br/></H2></center>";
html += "</body></html>";
espsend(html);
}
else
Serial.println("! Incoming connection - sending MAIN webpage");
String html = "";
html += "<html>";
html += "<body><center><H1>CONNECTED.<br/></H1></center>";
html += "<center><a href='/SERA'><h4>INFO:Get Sensor Data</a></br><a href='/WATERING'>WATERING:Run Water Pump</a></h4></center>";
html += "</body></html>";
espsend(html);
String closeCommand = "AT+CIPCLOSE="; ////////////////close the socket connection////esp command
closeCommand += connectionId; // append connection id
closeCommand += "\r\n";
sendData(closeCommand, 3000, DEBUG);
}
}
//////////////////////////////sends data from ESP to webpage///////////////////////////
void espsend(String d)
{
String cipSend = " AT+CIPSEND=";
cipSend += connectionId;
cipSend += ",";
cipSend += d.length();
cipSend += "\r\n";
sendData(cipSend, 1000, DEBUG);
sendData(d, 1000, DEBUG);
}
//////////////gets the data from esp and displays in serial monitor///////////////////////
String sendData(String command, const int timeout, boolean debug)
{
String response = "";
Serial1.print(command);
long int time = millis();
while ( (time + timeout) > millis())
{
while (Serial1.available())
{
char c = Serial1.read(); // read the next character.
response += c;
}
}
if (debug)
{
Serial.print(response); //displays the esp response messages in arduino Serial monitor
}
return response;
}
Project Proposal 💡
In the smart greenhouse project, by adding an OLED screen to the greenhouse entrance, you can monitor the humidity and temperature values inside, and by adding sensors such as MQ2 gas sensor, carbon dioxide sensor, air quality sensor, you can monitor the weather inside the greenhouse via WiFi with your mobile phone. In addition, by adding a DC fan and relay to the greenhouse, you can turn the ventilation on and off according to the indoor air quality with a mobile phone via WiFi.