Weather House

by Basheer bk in Craft > Art

109 Views, 1 Favorites, 0 Comments

Weather House

TEMp.png

A weather house is a folk art device in the shape of a small German or Alpine chalet that indicates the weather. A typical weather house has two doors side by side. The left side has a girl or woman, the right side a boy or man. The female figure comes out of the house when the weather is sunny and dry, while the male (often carrying an umbrella) comes out to indicate rain. according to resources , its used as a common home decor back in 1700s. it blend of art, craft and creativity science. in order to make a replica of it, i blended art with modern web technologies and electronics. we used open weather api to get humidity data and a servo for mechanical movement. the old weather house used some of hair mechanism to get atmosphere humidity, click here for more details of german weather house.

Supplies

IMG_20250527_221522087~2.jpg
IMG_20250523_190244369.jpg

seeed xiao ESP32S3

OLED Display

SG90 Servo motor

3MM form board

Glue

Solder iron

etc....

Making a House Model

IMG_20250521_223755668.jpg
IMG_20250521_223734150.jpg
Using 3MM form board sheet to make house model. first cut down the front portion which include two windows, then cutdown side and backside portion and stick whole this together. "This depends upon your creativity"

Sticking Paper Sheets

IMG_20250521_231612726.jpg
IMG_20250521_235022436.jpg
IMG_20250523_125550640.jpg

In order to get a wooden finish, i used wooden sticker sheet. For some glossy look i used yellow and reds color to the roof.

Attaching Servo

IMG_20250523_125554857.jpg
IMG_20250523_093938477.jpg

The SG90 servo motor is place correctly at the centre

Attaching Characters & Roof

IMG_20250526_222328826.jpg
IMG_20250526_221854848.jpg
IMG_20250526_223009642.jpg
IMG_20250523_133545285.jpg
IMG_20250523_163208479.jpg

Downloaded and printed an image of girl and boy with umbrella and for some texture look of the house , printed a brick wall image and sticked on lower wall side.

Circuit

cicurit.png

The servo motor and oled display are connected as per the circuit diagram.

OLED to Xiao ESP32S3

  1. SCL to SCL (D5).
  2. SDA to SDA (D4).
  3. GND to GND.
  4. VCC to 5v.

SERVO to Xiao ESP32S3

  1. VCC to 5v
  2. GND to GND
  3. Signal to D10


Api

Screenshot 2025-05-27 220138.png
Screenshot 2025-05-27 220157.png

For getting humidity details, we are using open weather forecast api. in the website you can set the longitude and latitude of your location and get access to the api. copy the access url.

Code

#include <WiFi.h>
#include <HTTPClient.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <ArduinoJson.h>
#include <ESP32Servo.h>
#include <time.h> // For time functions

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

const char* ssid = " "; //wifi-name
const char* password = " ";//wifi-passwd

const char* apiURL = " "; //Enter api access url here.

Servo weatherServo;
const int servoPin = 13;

const char* ntpServer = "pool.ntp.org";
const long gmtOffset_sec = 19800; // +5:30 IST
const int daylightOffset_sec = 0;

void setup() {
Serial.begin(115200);

if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println("SSD1306 allocation failed");
for (;;) ;
}
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);

weatherServo.attach(servoPin);
delay(1500);
weatherServo.write(90); // Neutral position
delay(1500);

WiFi.begin(ssid, password);
display.setCursor(0, 0);
display.println("Connecting WiFi...");
display.display();

while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}

display.clearDisplay();
display.setCursor(0, 0);
display.println("WiFi Connected!");
display.display();

configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
Serial.println("Waiting for NTP time sync...");
time_t now = time(nullptr);
while (now < 8 * 3600 * 2) {
delay(500);
Serial.print(".");
now = time(nullptr);
}
Serial.println("\nTime synchronized!");
}

void loop() {
if (WiFi.status() == WL_CONNECTED) {
HTTPClient http;
http.begin(apiURL);
int httpCode = http.GET();

if (httpCode > 0) {
String payload = http.getString();
Serial.println(payload);

DynamicJsonDocument doc(4096);
DeserializationError error = deserializeJson(doc, payload);

if (!error) {
time_t now = time(nullptr);
struct tm* timeinfo = localtime(&now);
int currentHour = timeinfo->tm_hour;

JsonArray tempArray = doc["hourly"]["temperature_2m"].as<JsonArray>();
JsonArray humidityArray = doc["hourly"]["relative_humidity_2m"].as<JsonArray>();

if (currentHour < tempArray.size() && currentHour < humidityArray.size()) {
float temperature = tempArray[currentHour];
float humidity = humidityArray[currentHour];

display.clearDisplay();

// Temperature
display.setTextSize(1);
display.setCursor(0,5);
display.println("Temp.");
display.setCursor(0, 30);
display.setTextSize(2);
display.print(temperature, 1);
display.setCursor(50, 37.5);
display.setTextSize(1);
display.println("C");
//Humidity
display.setTextSize(1);
display.setCursor(70, 5);
display.println("Humidity");
display.setCursor(70, 30);
display.setTextSize(2);
display.print(humidity,1);
display.setCursor(120, 35);
display.setTextSize(1);
display.println("%");

display.setTextSize(1);
display.setCursor(50, 55);

if (humidity >= 60) {
display.print("Rainy");
delay(1500);
weatherServo.write(180);
delay(1500);
} else {
delay(1500);
display.print("Sunny");
delay(1500);
}

display.display();
} else {
Serial.println("Hour out of range");
displayError("Hour out of range");
}
} else {
Serial.println("JSON Parsing Error");
displayError("JSON Error");
}
} else {
Serial.println("HTTP Request Failed");
displayError("HTTP Error");
}
http.end();
} else {
Serial.println("WiFi Disconnected");
displayError("WiFi Lost");
reconnectWiFi();
}

delay(60000);
}

void displayError(const char* msg) {
display.clearDisplay();
display.setTextSize(1);
display.setCursor(0, 20);
display.println(msg);
display.display();
delay(2000);
}

void reconnectWiFi() {
if (WiFi.status() != WL_CONNECTED) {
Serial.println("Attempting to reconnect WiFi...");
display.clearDisplay();
display.setCursor(0, 0);
display.setTextSize(1);
display.println("WiFi");
display.println("Recon...");
display.display();

WiFi.reconnect();

int attempts = 0;
while (WiFi.status() != WL_CONNECTED && attempts < 10) {
delay(1000);
attempts++;
Serial.print(".");
}

if (WiFi.status() == WL_CONNECTED) {
Serial.println("\nWiFi Reconnected!");
display.clearDisplay();
display.setCursor(0, 0);
display.println("WiFi OK!");
display.display();
} else {
Serial.println("\nWiFi Reconnection Failed");
display.clearDisplay();
display.setCursor(0, 0);
display.println("WiFi");
display.println("Failed!");
display.display();
delay(2000);
ESP.restart();
}
}
}

upload the code to xiao esp32s3 using any like arduino ide. Here you have to replace the api access url with with your url and netwok name password. you can also set the servo angle as your desired value.

Testing

IMG_20250518_192554391.jpg
IMG_20250518_191211645.jpg
IMG_20250525_131708275.jpg

Here you can see the wifi is connecting and Temperature & Humidity are showing on oled screen.

Final Result

TEMp.png

Here is the final look the weather house. if its rainny the male would come out and if its sunny the female would come out. you can also use sensor DHT11 for this project, if you want to keep it offline. this project was an integration pure STE(A)M since it contain everything. One thing which strike me was in the modern world we came everything less design, calling it as minimalist approach but olden design has its beauty and creativity. maybe we should blend both together.