#include "config.h"
#include <WiFi.h>
#include "Adafruit_MQTT.h"
#include "Adafruit_MQTT_Client.h"
#include "DHT.h"
// Pin & Sensor Configuration
#define DHTPIN 15
#define DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE);
// Wi-Fi & MQTT Setup
WiFiClient client;
Adafruit_MQTT_Client mqtt(&client, AIO_SERVER, AIO_SERVERPORT, AIO_USERNAME, AIO_KEY);
Adafruit_MQTT_Publish tempFeed(&mqtt, AIO_USERNAME "/feeds/temperature");
Adafruit_MQTT_Publish humidFeed(&mqtt, AIO_USERNAME "/feeds/humidity");
void setup() {
Serial.begin(115200);
WiFi.begin(WLAN_SSID, WLAN_PASS);
while (WiFi.status() != WL_CONNECTED) {
Serial.print(".");
delay(500);
}
Serial.println("\nConnected to WiFi");
dht.begin();
}
void loop() {
// Ensure MQTT connection
if (!mqtt.connected()) {
Serial.println("Connecting to MQTT...");
while (mqtt.connect() != 0) {
Serial.println("Retrying MQTT...");
delay(5000);
}
Serial.println("MQTT Connected.");
}
// Read DHT11 sensor
float temp = dht.readTemperature();
float humid = dht.readHumidity();
if (isnan(temp) || isnan(humid)) {
Serial.println("Failed to read DHT sensor!");
return;
}
// Publish sensor data
Serial.printf("Temp: %.2f°C | Humidity: %.2f%%\n", temp, humid);
tempFeed.publish(temp);
humidFeed.publish(humid);
delay(10000); // Wait 10 seconds before next reading
}
How the enviroment work
The rain conditions are determined by temperature and humidity. When the temperature rises above 24°C and humidity stays below 60%, there is no rain. However, if the temperature drops below 20°C and humidity exceeds 60%, rain begins to fall.
Rain occurs when the temperature decreases and humidity increases.

Rain will not occurs when the temperature increased and humidity decresed.

let baseTempFeedURL = "https://io.adafruit.com/api/v2/thanht0m/feeds/temperature-feed"
;
let baseHumidityFeedURL = "https://io.adafruit.com/api/v2/thanht0m/feeds/humidity-feed"
;
let terrain = [];
let rainDrops = [];
let waterLevel = 0;
let terrainWidth = 800;
let terrainHeight = 600;
let noiseScale = 0.02;
let temperatureData = []; // Array to store temperature data
let humidityData = []; // Array to store humidity data
let currentIndex = 0; // Index to track the current data point
function setup() {
createCanvas(terrainWidth, terrainHeight);
generateTerrain();
// Fetch historical data for the specified date range
fetchHistoricalData("2025-02-12T11:11:00Z");
}
function draw() {
// Draw sky based on temperature
drawSky();
// Draw terrain
drawTerrain();
// Simulate rain based on humidity
if (humidityData.length > 0 && humidityData[currentIndex].value >= 60) {
simulateRain();
}
// Draw river
drawRiver();
// Update water level
updateWaterLevel();
// Draw vegetation
drawVegetation();
// Display current data
displayCurrentData();
}
function generateTerrain() {
for (let x = 0; x < terrainWidth; x++) {
let noiseVal = noise(x * noiseScale);
let y = map(noiseVal, 0, 1, terrainHeight / 2, terrainHeight);
terrain[x] = y;
}
}
function drawSky() {
if (temperatureData.length > 0) {
let temperature = temperatureData[currentIndex].value;
if (temperature > 20) {
// Sunny sky
background(135, 206, 235); // Light blue
} else {
// Cloudy sky
background(169, 169, 169); // Gray
}
}
}
function drawTerrain() {
fill(34, 139, 34); // Green for terrain
noStroke();
beginShape();
vertex(0, terrainHeight);
for (let x = 0; x < terrainWidth; x++) {
vertex(x, terrain[x]);
}
vertex(terrainWidth, terrainHeight);
endShape(CLOSE);
}
function simulateRain() {
// Add new raindrops
if (frameCount % 5 === 0) {
rainDrops.push(new RainDrop(random(width), 0));
}
// Update and display raindrops
for (let i = rainDrops.length - 1; i >= 0; i--) {
rainDrops[i].fall();
rainDrops[i].display();
// Remove raindrops that hit the ground
if (rainDrops[i].y > terrain[rainDrops[i].x]) {
rainDrops.splice(i, 1);
waterLevel += 0.01; // Increase water level
}
}
}
function drawRiver() {
fill(0, 119, 190); // Blue for river
noStroke();
rect(0, terrainHeight - waterLevel, width, waterLevel);
}
function updateWaterLevel() {
// Gradually decrease water level over time
waterLevel = max(0, waterLevel - 0.005);
}
function drawVegetation() {
fill(0, 100, 0); // Dark green for vegetation
noStroke();
for (let x = 0; x < width; x += 20) {
let y = terrain[x];
let treeHeight = random(10, 30);
rect(x - 2, y - treeHeight, 4, treeHeight);
}
}
function displayCurrentData() {
if (temperatureData.length > 0 && humidityData.length > 0) {
let currentTemp = temperatureData[currentIndex].value;
let currentHumidity = humidityData[currentIndex].value;
let currentTime = new Date(temperatureData[currentIndex].created_at).toLocaleString();
fill(255);
textSize(16);
textAlign(LEFT, TOP);
text(`Date: ${currentTime}`, 10, 10);
text(`Temperature: ${currentTemp}°C`, 10, 30);
text(`Humidity: ${currentHumidity}%`, 10, 50);
}
}
class RainDrop {
constructor(x, y) {
this.x = x;
this.y = y;
this.speed = random(2, 5);
}
fall() {
this.y += this.speed;
}
display() {
fill(0, 0, 255); // Blue for raindrops
noStroke();
ellipse(this.x, this.y, 2, 5);
}
}
async function fetchHistoricalData(startTime, endTime) {
try {
// Fetch temperature data
let tempResponse = await fetch(
`${baseTempFeedURL}/data?start_time=${startTime}&end_time=${endTime}`,
{ headers: { "X-AIO-Key": aioKey } }
);
if (!tempResponse.ok) throw new Error(`HTTP error! status: ${tempResponse.status}`);
temperatureData = await tempResponse.json();
// Fetch humidity data
let humidityResponse = await fetch(
`${baseHumidityFeedURL}/data?start_time=${startTime}&end_time=${endTime}`,
{ headers: { "X-AIO-Key": aioKey } }
);
if (!humidityResponse.ok) throw new Error(`HTTP error! status: ${humidityResponse.status}`);
humidityData = await humidityResponse.json();
console.log("Temperature Data:", temperatureData);
console.log("Humidity Data:", humidityData);
// Start cycling through the data
setInterval(updateDataIndex, 1000); // Update data every second
} catch (error) {
console.error("Error fetching historical data:", error);
}
}
function updateDataIndex() {
if (currentIndex < temperatureData.length - 1 && currentIndex < humidityData.length - 1) {
currentIndex++;
} else {
currentIndex = 0; // Loop back to the start
}
}