THE PROBLEM
Wild pollinators are declining in Catalonia, and the regional plan PIPOL aimed to reverse this loss by 2030. In May 2025, the Barcelona City Council began installing 100 nests for wild bees and wasps across 25 parks (Barcelona City Council, 2025). But a nest is only a shelter. It is fixed, while a solitary bee’s needs change with every life stage.
Temperature is the major threat identified. In a field study of red mason bees, offspring survival fell as nest temperature rose, mostly because eggs failed to develop (Ostap-Chec et al., 2021). In the summer, female bees avoided nests that were hotter than 28 °C and in the winter, warm spells increase weight loss in overwintering bees (Apidologie, 2025). A static nest cannot answer this.
Our Question: Can the nest regulate its internal temperatures to adapt to the life stage of the bee?
THE PROPOSAL
We built a shade for these existing nest designs that chooses its position from three inputs in order to passively control internal conditions:
- Rain
- Internal Temperature
- External Temperature
The code equates a manually inputted month into a season and thereafter, life stage. The stage defines a temperature range, and the range determines the servo shade angle.

THE LOGIC

Rain overrides everything. If it is dry, the system cross-checks inside against outside, so that it regulates the nest using comparative data.
THE CODE
#include <Servo.h>
#include <Wire.h>
// #include <RTClib.h>
#include <DHT.h>
#include <DHT20.h>
#include <U8x8lib.h>
#define TEMP_OUT_PIN 2
#define WATER_PIN A1
#define LIGHT_OUT_PIN A6
#define myservo1_PIN 3
#define myservo2_PIN 6
Servo myservo1;
Servo myservo2;
// RTC_DS1307 rtc;
DHT exteriorSensor(TEMP_OUT_PIN, DHT11);
DHT20 interiorSensor;
U8X8_SSD1306_128X64_NONAME_HW_I2C screen(U8X8_PIN_NONE);
int target1 = 0;
int target2 = 0;
int myservo1_angle = 0; //Starting Angle of Servos
int myservo2_angle = 0;
float temp_in = 0.0;
float temp_out = 0.0;
int light_out = 0;
bool water = false;
unsigned long lastServoMove = 0; // Servo Movement Time
const unsigned long SERVO_INTERVAL = 45;
unsigned long lastSensorRead = 0; // Servo Reading Timing
const unsigned long SENSOR_INTERVAL = 3000;
float lower_limit; // Temperature Limits for Each Season
float upper_limit;
int month;
const char* getBeeLifeStage(int month) {
if (month == 3 || month == 4 || month == 5) {
return “Nesting”; //The organism prepares a nest, lays eggs, or establishes a place for reproduction.
}
else if (month == 6 || month == 7 || month == 8) {
return “Larva Dev”; //The young organism develops and grows.
}
else if (month == 9 || month == 10 || month == 11) {
return “Dormant”; //A period of reduced activity, growth, or metabolis
}
else {
return “Overwintering”; //The organism survives winter conditions, often by reducing activity and conserving energy.
}
}
void moveServos() {
if (millis() – lastServoMove >= SERVO_INTERVAL) {
lastServoMove = millis();
if (myservo1_angle < target1) { // Servo 1: move gradually towards target
myservo1_angle++;
}
else if (myservo1_angle > target1) {
myservo1_angle–;
}
if (myservo2_angle < target2) { // Servo 2: move gradually towards target
myservo2_angle++;
}
else if (myservo2_angle > target2) {
myservo2_angle–;
}
myservo1_angle = constrain(myservo1_angle, 0, 180); // Keep angles within safe limits
myservo2_angle = constrain(myservo2_angle, 0, 180);
myservo1.write(constrain(myservo1_angle, 5, 175)); // Send positions to servos
myservo2.write(constrain(180 – myservo2_angle, 5, 175));
}
}
void setup() {
Serial.begin(115200);
delay(1000);
screen.setBusClock(100000); //Set up the Display Screen
screen.begin();
screen.setFlipMode(1);
screen.setFont(u8x8_font_chroma48medium8_r);
screen.clear();
Serial.println(“Screen setup done”);
// rtc.adjust(DateTime(2026, 10, 23, 12, 5, 0)); // Set RTC to the date and time when this sketch was compiled… must be disabled after setting it the first time
exteriorSensor.begin();
interiorSensor.begin();
pinMode(WATER_PIN, INPUT);
myservo1.attach(myservo1_PIN);
myservo2.attach(myservo2_PIN);
myservo1.write(myservo1_angle);
myservo2.write(myservo2_angle);
}
void setSeasonLimits(int month) {
if (month >= 3 && month <= 5) { // Spring
lower_limit = 10;
upper_limit = 22;
} else if (month >= 6 && month <= 8) { // Summer
lower_limit = 18;
upper_limit = 28;
} else if (month >= 9 && month <= 11) { // Autumn
lower_limit = 7;
upper_limit = 15;
} else { // Winter
lower_limit = 1;
upper_limit = 5;
}
}
void loop() {
interiorSensor.read(); // Read interior temperature from DHT20
temp_in = interiorSensor.getTemperature();
temp_out = exteriorSensor.readTemperature(); // Read exterior temperature from DHT11
float temp_difference = temp_in – temp_out;
light_out = analogRead(LIGHT_OUT_PIN);
water = digitalRead(WATER_PIN);
// rtc.now().month();
month = ; // Manually Input the Month
const char* monthNames[] = {
“January”, “February”, “March”, “April”, “May”, “June”, “July”, “August”, “September”, “October”, “November”, “December”
};
screen.drawString(0, 0, “Month:”);
screen.drawString(6, 0, monthNames[month – 1]);
screen.drawString(0, 1, getBeeLifeStage(month));
setSeasonLimits(month);
if (water == HIGH) { // //Rain Detection
target1 = 110;
target2 = 110;
screen.drawString(0, 3, “Rain Detected”);
}
else {
screen.drawString(0, 3, “No Rain Detected”);
setSeasonLimits(month);
if (temp_in > upper_limit && temp_difference > 0) { // Nest is too hot and warmer than outside
target1 = 90;
target2 = 90;
}
else if (temp_in < lower_limit && temp_difference < 0) { // Nest is too cold and colder than outside
target1 = 45;
target2 = 45;
}
else { // Neither temperature comparison supports intervention
target1 = 0;
target2 = 0;
}
}
moveServos();
screen.drawString(0, 4, “Temp In:”);
screen.setCursor(8, 4);
screen.print(temp_in);
screen.drawString(0, 5, “Temp Out:”);
screen.setCursor(9, 5);
screen.print(temp_out);
screen.drawString(0, 6, “Light:”);
screen.setCursor(6, 6);
screen.print(light_out);
}
SCHEMATIC DIAGRAM

THE PROTOTYPE

CHALLENGES
- We initially planned to calibrate a real-time clock so that the system would read the month automatically. However, there were difficulties in coding it. As a quick alternative, we made the month a manual input.
- While writing the code, we realised that the shade angle was being informed by several inputs simultaneously. In order to prevent conflicting outputs, we had to define a priority order.
FUTURE EXPLORATIONS
- Fix the real-time clock in the code so that the month, stage and limits update automatically in order to optimise the system.
- Simulate sun paths and shade for different park positions in order to determine shade angles.
- The shade is a passive method as it only changes how much sun and rain reach the nest. The next step would be to add an active strategy, so the nest can be warmed or cooled towards the range for the bees’ life stage.
THE DEMONSTRATION