UMT Environment Monitoring System
by sitizulaikaa456 in Circuits > Raspberry Pi
37 Views, 0 Favorites, 0 Comments
UMT Environment Monitoring System
Environmental monitoring is essential for understanding surrounding conditions in applications such as smart agriculture, water management, and smart environments. This project presents a low-cost environmental monitoring system built using the Raspberry Pi Pico W, with sensor data collected from areas around Universiti Malaysia Terengganu (UMT). The system uses the Raspberry Pi Pico W’s built-in temperature sensor to monitor air temperature, an LDR sensor to detect day and night conditions based on ambient light intensity, a DS18B20 waterproof sensor to measure water temperature, and a DIY ultrasonic-based sensor to detect water level without direct contact. This project demonstrates how simple sensors and microcontroller technology can be combined to monitor real environmental conditions in a practical and beginner-friendly way.
Supplies
Electronic Part
- Light Dependent Resistor (LDR) Sensor - 1 unit
- DS18B20 Water Temperature Sensor - 1 unit
- 5VDC HC-SR04 Ultrasonic Sensor - 1 unit
- Resistor 0.25W 5% (15K) - 1 unit
- Raspberry Pi Pico Wireless - 1 unit
- Breadboard - 1 unit
- USB Micro B Cable - 1 unit
- Various jumper wires
Model Part
- Junction Box 6x8x3 (with 4 units of bolts) - 1 unit
- PVC pipe - 3 unit
- Vinyl Electrical Tape
Tools
- Hand drill
- Mini hand drill set
- Soldering iron
- Flat screwdriver
LDR, DS18B20, and Air Temperature Sensor Setup
In this step, the LDR (Light Dependent Resistor), DS18B20 waterproof temperature sensor, and the built-in temperature sensor of the Raspberry Pi Pico W are prepared for environmental monitoring. The LDR is connected to an analog input pin on the Pico W and is used to detect ambient light intensity, allowing the system to determine day and night conditions around the monitoring area.
The DS18B20 sensor is used to measure water temperature and communicates with the Pico W using the One-Wire protocol, requiring only power, ground, and a single data pin. At the same time, the Pico W’s built-in temperature sensor is utilized to measure air temperature, providing real-time ambient temperature data without the need for additional hardware.
Ultrasonic Water Level Sensor
In this step, an ultrasonic sensor is used to detect the water level by measuring the distance between the sensor and the water surface. A small junction box is modified by making two holes that fit the ultrasonic sensor’s transmitter and receiver. This setup allows the sensor to be securely mounted while protecting it from external environmental conditions.
The junction box is placed above the water surface, with the ultrasonic sensor facing downward. By measuring the distance from the bottom of the box to the water surface, the system can determine changes in water level without direct contact with the water. This DIY approach provides a simple, low-cost, and effective method for monitoring water levels.
The Code (MicroPhyton - Thonny IDE)
In this system, the sensors act as the eyes of the environment, while the Raspberry Pi Pico W serves as the brain by running the MicroPhyton program. The hardware cannot interpret itself on its own, so the software translates their signals, makes decisions, and communicates the result to the user. The LDR detects ambient light, allowing the system to distinguish between day and night. The DS18B20 measures water temperature, providing critical insight into the thermal condition of the monitored environment. Meanwhile, the HC-SR04 determines water level by calculating the distance from the sensor to the surface.
This script contains the logic that powers the dashboard. It sets up charts for water temperature and light intensity and updates the page dynamically with the latest readings. Although the code runs in a browser, it reflects the same kind of logic implemented in MicroPython on the Raspberry Pi Pico W, where sensor data is read, processed, and prepared for display. The program is written and uploaded using Thonny IDE, which provides an easy interface for editing MicroPython code, testing functions, and deploying the software to the Pico. This structure ensures that the microcontroller can continuously process sensor input, calculate values like water level percentage, and update outputs in real time.
1. Pi Pico W Sensor Setup and ThingSpeak Configuration
import machine,time,urequests
import onewire, ds18x20
# Pin Setup
LDR PIN = 26 # ADC pin for LDR
TRIG PIN = 3 # Ultrasonic trigger
ECHO PIN = 2 # Ultrasonic echo
DS18B20_PIN = 4 # DS18B20 data pin
Idr = machine. ADC (LDR_PIN)
trig = machine. Pin(TRIG_PIN, machine.Pin. OUT)
echo = machine. Pin(ECHO_PIN, machine. Pin. IN)
# DS18B20 setup
ow = onewire. Onewire(machine.Pin(DS18B20_PIN))
ds = ds18x20.DS18X20(OW)
roms = ds. scan() # scan for DS18B20 devices
# Built-in temperature sensor for air
air_temp_sensor = machine. ADC (4)
# ThingSpeak Contiguration
READ_API_KEY = "UFJUYMV2TOB4CY2K"
CHANNEL ID = 3218184"
TANK_MAX_DEPTH_CM = 100
LDR_THRESHOLD = 2000 # Value above this is considered DAY
2. Sensor Reading and Data Transmission Functions
#Functions
def read_1dr():
"''"Read LDR value (0-65535). "'"
return Idr. read_u16()
def read_air_temp():
"''"Convert Pico built-in sensor to Celsius.""'"
raw = air_temp_sensor. read_16)
voltage = raw / 65535 * 3.3
temp_c = 27 - (voltage - 0.706)/0.001721
return round (temp_c, 1)
def read_water_temp() :
"'"Read temperature from DS18B20. ""'"
ds. convert_temp)
time. sleep_ms (750)
temp = ds. read_temp(roms [0])
return round (temp, 1)
def read_distance):
"""Measure water level distance using HC-SR04. "''"
trig.low()
time. sleep_us (2)
trig.high()
time. sleep_us (10)
trig.Low()
while echo. value == 0:
pass
start = time. ticks_us ()
while echo. value() == 1:
pass
end = time.ticks_us()
duration = time.ticks_diff(end, start)
distance_cm = (duration * 0.0343) / 2
# Cap distance to tank max depth
distance_cm = max (0, min(TANK_MAX_DEPTH_C, distance_cm))
return round distance_cm,1)
def day_night_status (1dr_val):
"''"Determine if it's day or night based on threshold.""'" return 1 if Id_val > LDR_THRESHOLD else 0 # 1=Day, 0=Night
def send_to_thingspeak(light, water_temp, water_level, daynight, air_temp):
"''"Send all sensor data to Thingspeak. "''"
url = f"https://api.thingspeak.com/update?api_key=(READ_API_KEY) "
url += f"&field1=(light)&field2=(water_temp}&field3=(water_level)"
url += f"&field4=(daynight)&field5=(air_temp)"
try:
response = urequests.get(url)
response.close()
except:
print ("Failed to send data")
3. Main Loop - Continuous Monitoring and Data Upload
# Main Loop
while True:
light = read_Idr()
water_temp = read_water_temp)
water_level = read_distance ()
daynight = day_night_status (light)
air_temp = read_air_temp()
print ("LDR:", light, "water Temp:", water_temp",
"Water Level:", water_level, "Day/Night:", daynight,
"Air Temp:", air_temp)
send_to_thingspeak(light, water_temp, water_level, daynight, air_temp)
# Wait 30 minutes before sending next data
time. sleep(1800)
The Cloud (ThingSpeak Backend)
1. Channel Setup and Configuration
To start collecting sensor data in the cloud, we created a new ThingSpeak channel called "UMT Environment." This channel acts as the central storage for all our measurements. We set up five separate fields to match the outputs of our sensors, allowing each type of data to be tracked individually. By organizing the data this way, each sensor’s readings are easy to identify and analyze. These fields are:
- Field 1: Light Intensity
- Field 2: Water Temperature
- Field 3: Water Level
- Field 4: Day/Night Cycle
- Field 5: Air Temperature
2. Authenticating API Keys
To ensure that only our Raspberry Pi Pico W can send data to the channel, we used ThingSpeak’s API Key system. A Write API Key is generated from the ThingSpeak channel and added to the MicroPython program running on the Pico W. This key acts like a password, giving the microcontroller permission to safely upload data to the cloud without risking unauthorized access.
3. Verification
Once the system is running, the Pico W continuously reads data from all sensors and sends it to ThingSpeak. The dashboard automatically updates in real-time, displaying charts for each field. This lets us immediately see changes in light levels, water temperature, water height, day/night status, and air temperature. The automatic visualization confirms that the system is functioning correctly, providing a live view of environmental conditions.
Frontend Dashboard
ThingSpeak is utilized as the cloud platform for collecting and storing sensor data generated by the IoT system. However, to provide a clearer and more structured way of interpreting this data, a custom web dashboard named EcoMonitorPro was developed. This dashboard serves as the main visualization layer of the system, transforming numerical sensor readings into meaningful visual information that can be easily understood by users.
- Dashboard Design Approach
The design of EcoMonitorPro prioritizes clarity, simplicity, and functional layout. A light and neutral color scheme is used to reduce visual fatigue and to keep the user’s focus on the data itself. Information is organized into separate cards, each dedicated to a specific environmental parameter, ensuring that the interface remains structured and easy to navigate. The overall layout allows users to quickly assess environmental conditions without the need for technical expertise.
Functional Overview
- Water Temperature Monitoring:
Water temperature data collected from the DS18B20 sensor is displayed in degrees Celsius and accompanied by a line graph showing recent variations. This graphical representation enables users to observe temperature trends over time and identify any unusual changes that may indicate environmental anomalies.
- Light Intensity Measurement:
The light-dependent resistor (LDR) provides continuous measurements of ambient light intensity. These values are presented numerically and through a trend graph, allowing users to correlate light changes with time-based conditions such as sunrise and sunset.
- Automatic Day/Night Classification:
Based on the light intensity readings, the system automatically determines whether the environment is in a daytime or nighttime state. This status is shown clearly on the dashboard, reducing the need for users to interpret raw sensor values.
- Water Level Visualization:
Water level information obtained from the HC-SR04 ultrasonic sensor is converted from distance measurements into a visual water-level indicator. Displaying this data in a tank-style graphic makes it easier for users to understand current water conditions at a glance.
- Data Visualization and Accessibility
Rather than displaying raw datasets, EcoMonitorPro emphasizes visual trend analysis through line charts and graphical indicators. This approach improves readability and helps users recognize patterns and changes in environmental conditions over time. The dashboard is also designed to be responsive, ensuring consistent usability across different devices and screen sizes.
- System Integration and Data Flow
The IoT system follows a structured data flow architecture. Sensor data is transmitted from the microcontroller to ThingSpeak using a Write API Key. The dashboard then retrieves the most recent data entries through a Read API Key and updates the displayed values dynamically. This separation between data collection, storage, and visualization improves system reliability and supports future scalability.
Overall, EcoMonitorPro provides an effective interface for monitoring environmental parameters by combining real-time data access with clear visual presentation, enhancing both usability and interpretability of the IoT system.
code for dashboard:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>IoT Campus Environmental Monitoring</title>
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://unpkg.com/lucide@latest"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<style>
.tank-container{
position:relative;
height:16rem;
width:8rem;
background:#f1f5f9;
border-radius:0.5rem;
border:2px solid #cbd5e1;
overflow:hidden;
margin:auto;
}
.water{
position:absolute;
bottom:0;
width:100%;
background:#3b82f6;
transition:height 1s ease;
opacity:.8;
}
.water-surface{
height:6px;
background:#60a5fa;
animation:pulse 2s infinite;
}
@keyframes pulse{0%,100%{opacity:.5}50%{opacity:.8}}
</style>
</head>
<body class="bg-slate-50 text-slate-800">
<nav class="bg-white border-b px-6 py-4 flex justify-between items-center shadow-sm">
<h1 class="text-xl font-bold">EcoMonitor<span class="text-blue-600">Pro</span></h1>
<span id="last-updated" class="text-xs text-slate-500">Waiting for data…</span>
</nav>
<main class="max-w-7xl mx-auto px-6 mt-8 grid grid-cols-1 lg:grid-cols-3 gap-6">
<!-- LEFT -->
<div class="lg:col-span-2 space-y-6">
<!-- DS18B20 -->
<div class="bg-white p-5 rounded-xl border shadow-sm">
<h3 class="font-semibold mb-1">Water Temperature (DS18B20)</h3>
<div class="text-4xl font-bold">
<span id="val-temp">--</span> °C
</div>
<div class="h-20 mt-3"><canvas id="chart-temp"></canvas></div>
</div>
<!-- LDR -->
<div class="bg-white p-5 rounded-xl border shadow-sm">
<h3 class="font-semibold mb-1">Light Intensity (LDR)</h3>
<div class="text-4xl font-bold">
<span id="val-ldr">--</span>
</div>
<div class="h-20 mt-3"><canvas id="chart-ldr"></canvas></div>
</div>
<!-- DAY / NIGHT -->
<div class="bg-white p-5 rounded-xl border shadow-sm text-center">
<h3 class="font-semibold mb-2">Day / Night Status</h3>
<span id="val-daynight"
class="px-4 py-2 rounded-full text-sm font-bold bg-slate-200">
--
</span>
</div>
</div>
<!-- RIGHT -->
<div class="bg-white p-6 rounded-xl border shadow-sm space-y-6">
<h3 class="font-semibold">Water Level Monitor (HC-SR04)</h3>
<div class="tank-container">
<div id="tank-water" class="water" style="height:0%">
<div class="water-surface"></div>
</div>
<div class="absolute bottom-2 w-full text-center">
<span id="tank-label"
class="text-xs font-bold bg-white/80 px-2 py-1 rounded">
-- cm
</span>
</div>
</div>
<div class="flex justify-between text-sm">
<span>Distance</span>
<span id="val-dist" class="font-bold text-blue-600">-- cm</span>
</div>
</div>
</main>
<footer class="text-center text-xs text-slate-400 mt-10 pb-6">
© 2026 UMT IoT Group Project · ThingSpeak
</footer>
<script>
lucide.createIcons();
const READ_API_KEY = "UFJUYMV2TOB4CY2K";
const CHANNEL_ID = "3218184";
const TANK_MAX_DEPTH_CM = 100;
const chartOpts = {
responsive:true,
maintainAspectRatio:false,
plugins:{legend:{display:false}},
scales:{x:{display:false},y:{display:false}},
elements:{point:{radius:0},line:{tension:.4}}
};
const chartTemp = new Chart(
document.getElementById("chart-temp"),
{type:"line",data:{labels:[],datasets:[{data:[],borderColor:"#f97316"}]},options:chartOpts}
);
const chartLdr = new Chart(
document.getElementById("chart-ldr"),
{type:"line",data:{labels:[],datasets:[{data:[],borderColor:"#22c55e"}]},options:chartOpts}
);
async function fetchData(){
const res = await fetch(`https://api.thingspeak.com/channels/${CHANNEL_ID}/feeds.json?api_key=${READ_API_KEY}&results=20`);
const data = await res.json();
if(!data.feeds.length) return;
const feeds = data.feeds;
const last = feeds.at(-1);
const ldr = parseFloat(last.field1);
const waterTemp = parseFloat(last.field2);
const distance = parseFloat(last.field3);
const dayNight = parseInt(last.field4);
document.getElementById("val-temp").innerText = isNaN(waterTemp)?"--":waterTemp.toFixed(1);
document.getElementById("val-ldr").innerText = isNaN(ldr)?"--":ldr;
document.getElementById("val-dist").innerText = isNaN(distance)?"-- cm":distance.toFixed(1)+" cm";
const date = new Date(last.created_at);
document.getElementById("last-updated").innerText = date.toLocaleTimeString();
// Day / Night
const dn = document.getElementById("val-daynight");
if(dayNight===1){
dn.innerText="DAY ☀️";
dn.className="px-4 py-2 rounded-full text-sm font-bold bg-yellow-100 text-yellow-800";
}else{
dn.innerText="NIGHT 🌙";
dn.className="px-4 py-2 rounded-full text-sm font-bold bg-indigo-100 text-indigo-800";
}
// Tank
if(!isNaN(distance)){
let water = TANK_MAX_DEPTH_CM - distance;
water = Math.max(0,Math.min(TANK_MAX_DEPTH_CM,water));
const pct = (water/TANK_MAX_DEPTH_CM)*100;
document.getElementById("tank-water").style.height = pct+"%";
document.getElementById("tank-label").innerText = water.toFixed(1)+" cm Water";
}
chartTemp.data.labels = feeds.map(f=>new Date(f.created_at).toLocaleTimeString());
chartTemp.data.datasets[0].data = feeds.map(f=>f.field2);
chartTemp.update();
chartLdr.data.labels = feeds.map(f=>new Date(f.created_at).toLocaleTimeString());
chartLdr.data.datasets[0].data = feeds.map(f=>f.field1);
chartLdr.update();
}
fetchData();
setInterval(fetchData,15000);
</script>
</body>
</html>
Pre-Deployment Validation (Group Test)
Before proceeding with the long-term deployment, a pre-deployment validation phase was conducted to ensure the reliability and stability of the IoT system under real environmental conditions. This stage focused on verifying sensor accuracy, system responsiveness, and network stability through group-based field testing.
1. Initial Deployment Attempt: Pusat Islam Sultan Mahmud
The first planned deployment location was Pusat Islam Sultan Mahmud, specifically near the wudhu’ area where water usage is frequent and suitable for environmental monitoring. The IoT device was installed and monitored collectively by the group to observe real-time sensor behavior and data transmission.
During this phase, all sensors functioned correctly, and data was successfully transmitted to ThingSpeak and displayed on the dashboard. However, after approximately three hours of continuous operation, the system experienced repeated WiFi disconnections. Despite multiple reconnection attempts, the instability persisted, indicating that the available network coverage at the site was not reliable for long-duration IoT deployment.
Based on this observation, the group concluded that proceeding with this location would risk incomplete data collection and system downtime.
2. Relocation and Validation at Hatchery ENOS, UMT
To address the connectivity issue, the group relocated the IoT system to Hatchery ENOS, UMT, an area with more stable WiFi coverage and a suitable aquatic environment for testing. This relocation allowed the team to re-evaluate the system under improved network conditions while maintaining relevance to the project’s monitoring objectives.
3. Group-Based Validation Procedures
- Physical Observation and Sensor Response Check
The group observed the physical environment directly while simultaneously monitoring the dashboard readings. Water level changes, temperature variation, and light intensity were cross-checked with actual conditions at the site to confirm that sensor outputs were reasonable and responsive.
- Continuous Operation Monitoring
The system was left running for an extended period to assess stability. Unlike the earlier site, the IoT device at Hatchery ENOS maintained a stable WiFi connection without unexpected disconnections. Data updates remained consistent, confirming that the system could support long-term deployment.
- Group Verification and Consensus
All group members participated in observing the system’s performance and dashboard updates. Agreement among the team regarding data consistency and system behavior provided additional confidence that the readings were reliable and not the result of individual interpretation or error.
4. Outcome of the Group Test
The pre-deployment group test successfully validated that:
- Sensor readings accurately reflected real environmental conditions.
- The dashboard correctly displayed real-time data updates.
- Network stability was a critical factor in deployment site selection.
- Hatchery ENOS, UMT was a suitable and reliable location for the final deployment.
This validation phase ensured that the system was technically ready and environmentally compatible before entering the official deployment period.
Deployment
After successing in the pre-deployment, the system is finally being deployed at the actual site. The system was deployed behind the UMT Hatchery area, near the water source. The system hardwares are being placed in the box and the box is properly sealed with tape to make sure the hardwares and sensors doesn't get affected by the rain water or even any unexpected incident. The box was being placed on a stable surface and to really secure the box from falling into the water, stones are stacked on top of it.
The cable for water temperature sensor was safely placed in the water and the water level sensor was being placed accordingly where it doesn't get covered with anything that might affect the data entries.
The system was fully powered by a power bank. After testing and figuring out the best choice for the power supply, we finally deployed the system using a power bank that doesn't cut off the power supply after minutes or hours of being turned on. But to acquire a consistent data, the power supply is regularly being checked on by every group members.
Maintenance & Challenges
As for maintenance, we regularly check on our hardwares by checking if there are any water entering the box and ruining the sensors and hardwares. We also regularly come to check the box placement due to the unpredictable weather such as the strong winds that might push the box off the spot we placed it and a sudden heavy rain.
The power supply comes in handy because it doesn't cut off power automatically after minutes or hours of operating. But to ensure data consistency, we regularly come to check on the battery percentages.
The challenge we faced was mainly about keeping the hardware box secure from the rain water to get inside. Since we did some DIY on the box where we make holes to put our sensor and also attaching half an empty bottle to it to put the LDR sensor, the rain water somehow got into the bottle. Fortunately, our sensors are safe. The next time we deployed the system, we put around extra tape on the bottle to make sure the rain water doesn't get in.
We also face problem with data inconsistency for the LDR and Ultrasonic sensor and issue with the coding. The data entries are too inconsistent causing us to update the code regularly to make sure it align with the day & night and also the water level.
Disassembly
After completing the 7-day deployment period at UMT Lake, the IoT monitoring station was safely disassembled to ensure compliance with the “Leave No Trace” requirement stated in the project guidelines.
The disassembly process involved:
1. Power Shutdown & Safety
- The device was first disconnected from the power bank to prevent any electrical hazards during handling.
- The casing was checked to ensure no condensation or moisture trapped inside.
2. Removal of Device from Deployment Site
- The waterproof enclosure containing the Pico W, sensor modules, and wiring harness was carefully detached from the mounting surface.
- Zip ties and mounting clips were removed without damaging any natural or man-made property at the deployment location.
3. Sensor Extraction & Component Recovery
- All sensors (AHT20/BMP280 unit, DS18B20 stainless steel probe, and HC-SR04 unit) were detached from the casing.
- Jumper wires and connectors were recovered for reuse to reduce project cost and e-waste.
4. Cleaning and Post-Inspection
- Components were cleaned to remove dust, algae mist, and water residue accumulated during deployment.
- Each sensor was tested again indoors to verify post-deployment health and ensure they maintained normal output readings.
5. Site Restoration
- No physical marks, drilling, adhesives, or invasive fixtures were used.
- The location was restored to its original condition in accordance with the ethical requirement “device must be non-invasive and temporary.”