An Arduino-based IoT weather station that measures wind speed and sound intensity, transmitting real-time data to a cloud database via MQTT over Ethernet.
Built as part of the Embedded Systems Project Work course at Tampere University of Applied Sciences (TAMK), Spring 2025.
- Overview
- System Architecture
- Hardware Components
- Software Design
- Test Cases
- Getting Started
- Project Structure
- Team
The weather station collects two environmental parameters:
| Parameter | Sensor | Interface |
|---|---|---|
| Sound Intensity | DFRobot Gravity Analog Sound Sensor (DFR0034) | Analog (A0) |
| Wind Speed | Anemometer signal box (lab) | Digital interrupt (Pin 2) |
Data is processed by an Arduino Nano/Mega and published to an MQTT broker every 5 seconds. The broker forwards data to a cloud SQL database, retrievable via a REST API.
Wind speed is calculated using the anemometer transfer function:
U (m/s) = -0.24 + F (Hz) × 0.699
┌─────────────────────────────────────────────────────┐
│ IoT Layer Stack │
│ │
│ [Sound Sensor] [Wind Sensor/Anemometer] │
│ │ │ │
│ └──────┬───────────┘ │
│ ▼ │
│ [Arduino Nano] ← Device Layer │
│ (C++ Firmware) │
│ │ │
│ ▼ │
│ [Ethernet Shield W5100] ← Gateway Layer │
│ │ │
│ ▼ │
│ [MQTT Broker :1883] ← Cloud Layer │
│ │ │
│ ▼ │
│ [SQL Database + REST API] │
└─────────────────────────────────────────────────────┘
| Component | Specification | Function |
|---|---|---|
| Microcontroller | Arduino Mega / Nano | Central processing unit |
| Sound Sensor | DFRobot DFR0034 | Analog sound intensity measurement |
| Wind Sensor | Signal box (anemometer output) | Frequency-based wind speed input |
| LCD Display | 20×4 Character LCD | Real-time local data display |
| Ethernet Module | W5100-based shield | TCP/IP network connectivity |
| Push Button | With 10 kΩ pull-down resistor | Transmission mode selector |
Pin Mapping:
| Pin | Connected To |
|---|---|
| A0 | Sound sensor (analog) |
| D2 | Wind sensor (external interrupt, falling edge) |
| D3–D8 | LCD display (parallel interface) |
| D9 | Push button (mode select) |
| Library | Purpose |
|---|---|
LiquidCrystal.h |
LCD display control |
TimerOne.h |
Hardware timer interrupt (1 s tick) |
Ethernet.h |
W5100 Ethernet shield / DHCP |
PubSubClient.h |
MQTT client (publish/subscribe) |
| Function | Description |
|---|---|
pulseISR() |
Counts falling edges from wind sensor on Pin 2 |
timerISR() |
Fires every 1 s; calculates frequency over a 10 s gate |
readAverageAnalog() |
Averages N ADC samples with configurable delay |
handleButton() |
Cycles transmission mode with 50 ms debounce |
publishData() |
Builds JSON payload and publishes to MQTT topic |
connectMQTT() |
Handles MQTT broker connection and reconnection |
updateDisplay() |
Refreshes 20×4 LCD with current sensor values |
Controlled by a push button — cycles through three modes:
[Default: ANALOG] → [DIGITAL] → [BOTH] → [ANALOG] → ...
| Mode | Data Sent |
|---|---|
ANALOG |
Sound intensity only |
DIGITAL |
Wind speed only |
BOTH |
Sound intensity + Wind speed |
IOTJS={"S_name1":"EMB_sound","S_value1":245,"S_name2":"EMB_windSpeed","S_value2":312}Three formal test cases were executed to verify system correctness.
Objective: Verify that readAverageAnalog() stabilises noisy ADC readings.
| Environment | Raw ADC Range | Averaged Output |
|---|---|---|
| Quiet room | 0 – 50 | Stable ~5–10 |
| Loud environment | 100 – 500 | Stable ~300 |
✅ Result: Averaging function correctly reduced noise in all conditions.
Objective: Verify frequency measurement and MQTT connectivity using a signal generator.
Signal generator settings used:
- Amplitude: 2.5 V (peak-to-peak)
- Offset: 1.25 V
- Frequency range tested: 1 Hz – 50 kHz
All wind speed outputs verified manually against the transfer function U = -0.24 + F × 0.699.
✅ Result: Frequency measurement accurate across full tested range. MQTT broker connection confirmed.
Objective: Confirm sensor data is stored in the remote SQL database and retrievable via REST API.
API endpoints tested:
GET /v1/weather/latest/EMB_windSpeed
GET /v1/weather/latest/EMB_sound
Both returned valid JSON with current readings and timestamps. Historical endpoints confirmed persistent storage.
✅ Result: Full pipeline — sensor → Arduino → MQTT → database → REST API — verified successfully.
- Arduino IDE (v1.8+ or v2.x)
- Required libraries (install via Arduino Library Manager):
TimerOnePubSubClientby Nick O'LearyEthernet(built-in)LiquidCrystal(built-in)
-
Clone this repository:
git clone https://github.com/YOUR_USERNAME/iot-weather-station.git cd iot-weather-station -
Open the sketch:
Open src/weather_station/weather_station.ino in Arduino IDE -
Configure your network in
weather_station.ino:byte mqttServerIP[] = { YOUR, MQTT, BROKER, IP }; static uint8_t mymac[6] = { 0x44, 0x76, 0x58, 0x10, 0x00, 0x62 }; // update MAC -
Upload to your Arduino Mega/Nano with the Ethernet shield connected.
- Connect the sound sensor to pin A0
- Connect wind sensor signal to pin D2 (interrupt-capable)
- Wire LCD to pins D3–D8 (RS=8, EN=7, D4=6, D5=5, D6=4, D7=3)
- Connect push button to pin D9 with a 10 kΩ pull-down resistor to GND
- Attach Ethernet shield on top of the Arduino
iot-weather-station/
│
├── src/
│ └── weather_station/
│ └── weather_station.ino # Main Arduino sketch
│
├── docs/
│ ├── FINAL_REPORT.pdf # Full technical report
│ └── circuit_diagram.png # Hardware wiring diagram (add yours)
│
├── test/
│ └── test_cases.md # Formal test case documentation
│
├── .gitignore
├── LICENSE
└── README.md
EMB Group — TAMK Software Engineering, 2025
- Sasnu Fernando
- Piyumi Gajanayaka
- Geethika Jayasekara
- Sachini Alwis
This project is licensed under the MIT License — see LICENSE for details.