The ESP32 weather station retrieves current and historical weather data from a REST API server. The system uses HTTP/HTTPS to fetch:
- Current Weather: Real-time sensor readings from
/currentendpoint - Historical Data: Time-series data from
/historyendpoint
#define WEBSERVER_URL "http://your-server.example.com/weatherAPI"Examples:
http://192.168.1.100/weatherAPI- Local serverhttps://api.example.com/weather- HTTPS with custom domainhttp://weather.local:8080/api- Custom port
#define HTTP_CURRENT_ENDPOINT "/current"
#define HTTP_HISTORY_ENDPOINT "/history"
#define HTTP_TIMEOUT_MS 10000Request:
GET /current
Response Format:
{
"temperature": 23.5,
"humidity": 65.2,
"pressure": 1013.2,
"wind_speed": 5.3,
"wind_direction": 245,
"wind_gust": 8.1,
"rainfall": 2.5,
"timestamp": 1704312000
}Required Fields:
temperature- Temperature in Celsius (float)humidity- Relative humidity 0-100% (float)pressure- Air pressure in millibars/hPa (float)wind_speed- Wind speed in m/s (float)wind_direction- Wind direction in degrees 0-359 (integer)wind_gust- Wind gust speed in m/s (float)rainfall- Rainfall in millimeters (float)timestamp- Unix timestamp in seconds (integer)
Request:
GET /history
Query Parameters (optional):
days=7- Number of days of history (default: 7)resolution=1h- Data granularity (default: 1h)
Query Parameters (optional):
days=7- Number of days of history (default: 7)resolution=1h- Data granularity (default: 1h)
Example Requests:
GET /history
GET /history?days=7&resolution=1h
GET /history?days=3&resolution=5m
Response Format:
[
{
"timestamp": 1704225600,
"temperature": 22.0,
"humidity": 60.5,
"pressure": 1012.5,
"wind_speed": 4.2,
"wind_direction": 180,
"rainfall": 0.5
},
{
"timestamp": 1704229200,
"temperature": 23.1,
"humidity": 58.5,
"pressure": 1013.1,
"wind_speed": 5.1,
"wind_direction": 200,
"rainfall": 1.2
}
]Required Fields per Data Point:
timestamp- Unix timestamp in seconds (integer)temperature- Temperature in Celsius (float)humidity- Relative humidity 0-100% (float)wind_speed- Wind speed in m/s (float)rainfall- Rainfall in millimeters (float)
Optional Fields:
pressure- Air pressure in millibars (float)wind_direction- Wind direction in degrees (integer)*_min,*_max- Min/max values for range display
| Resolution | Description | Data Points (7 days) | Use Case |
|---|---|---|---|
raw |
Raw sensor readings | ~100,000+ | Real-time display (minutes) |
5m |
5-minute aggregates | 2,016 | Recent detailed history (hours) |
1h |
Hourly aggregates | 168 | Default - Weekly charts |
1d |
Daily aggregates | 7 | Long-term trends (months) |
Current Setting: 1h (168 data points for 7 days)
The resolution parameter controls data point granularity:
| Resolution | Description | Data Points (7 days) | Use Case |
|---|---|---|---|
raw |
Raw sensor readings | ~100,000+ | Real-time display (seconds/minutes) |
5m |
5-minute aggregates | 2,016 | Recent detailed history (hours/day) |
1h |
Hourly aggregates | 168 | Default - Weekly charts |
1d |
Daily aggregates | 7 | Long-term trends (months/years) |
Current Setting: 1h (168 data points for 7 days)
This provides optimal balance for:
- Memory Usage: ESP32 has limited RAM (~300KB available)
- Display Resolution: 960×540 E-paper display
- Update Frequency: 60-second wake cycles with light sleep
For advanced implementations, the API may return min/max ranges:
[
{
"timestamp": 1704225600,
"temperature": 22.0,
"temperature_min": 21.5,
"temperature_max": 22.8,
"humidity": 60.5,
"humidity_min": 59.8,
"humidity_max": 61.2,
"pressure": 1012.5,
"pressure_min": 1012.3,
"pressure_max": 1012.7,
"wind_speed": 4.2,
"wind_speed_min": 2.1,
"wind_speed_max": 7.5,
"wind_direction": 180,
"rainfall": 0.5,
"rainfall_min": 0.0,
"rainfall_max": 1.2
}
]The ESP32 currently uses only the average values:
timestamp- Required for time-series plottingtemperature- Average temperature (°C)humidity- Average humidity (%)wind_speed- Average wind speed (m/s)rainfall- Accumulated rainfall (mm)
The *_min and *_max fields can be used for:
- Error bars on charts showing data variability
- Temperature range displays (e.g., "22-25°C")
- Highlighting extreme values or anomalies
- More detailed weather pattern analysis
-
Wake from Light Sleep (every 60 seconds)
- Timer wakeup in main loop
-
HTTP Request
weather.fetchCurrentWeather()calls HTTP client- GET request to
WEBSERVER_URL + /current
-
Response Handling
- HTTP callback receives JSON data
- cJSON library parses response
-
Data Storage
- Current weather data stored in
WeatherDatasingleton - Used by UI widgets: thermometer, wind rose, status bar
- Current weather data stored in
-
Display Update
ui.update()triggers re-render- E-paper display shows updated values
-
Periodic Fetch (on display update)
weather.fetchHistoricalData()in WeatherUI
-
HTTP Request
- GET request to
WEBSERVER_URL + /history - Fetches 7 days of hourly data (168 points)
- GET request to
-
JSON Parsing
- Parses array of historical data points
- Extracts timestamp, temperature, humidity, wind_speed, rainfall
-
Data Storage
- Stores up to
MAX_HISTORY_POINTS(168 by default) - Historical array in
WeatherDataclass
- Stores up to
-
Chart Rendering
Chartwidgets read historical data- Line charts drawn on E-paper display
- 168 data points × ~32 bytes/point = ~5.4KB
- Plus JSON parsing buffer (~16KB)
- Total: ~21KB RAM usage for historical data
If memory becomes an issue:
Option 1: Reduce time range
// In config.h - modify HTTP_HISTORY_ENDPOINT
#define HTTP_HISTORY_ENDPOINT "/history?days=3" // 72 points (~2.3KB)Option 2: Use daily aggregates
#define HTTP_HISTORY_ENDPOINT "/history?days=30&resolution=1d" // 30 points (~1KB)Option 3: Reduce buffer size
// In http_client.c - reduce MAX_BUFFER_SIZE if responses are predictable
#define MAX_BUFFER_SIZE (8192) // Instead of 16384The system handles various failure scenarios:
- HTTP timeout (10 seconds default)
- Connection failures
- DNS resolution errors
Behavior: Logs warning, continues with cached/previous data
- Invalid JSON format
- Missing required fields
- Type mismatches
Behavior: Logs error, skips invalid entries, uses partial data if available
- Checks for array type in historical data
- Validates timestamp presence (required field)
- Handles missing optional fields (uses default values)
- Range checks for sensor values
curl "http://your-server.example.com/weatherAPI/current"Expected Response:
{
"temperature": 23.5,
"humidity": 65.2,
"pressure": 1013.2,
"wind_speed": 5.3,
"wind_direction": 245,
"wind_gust": 8.1,
"rainfall": 2.5,
"timestamp": 1704312000
}curl "http://your-server.example.com/weatherAPI/history" | jq lengthExpected: Should return number between 1-168 (or your configured days × 24)
# Test different resolutions
curl "http://your-server.example.com/weatherAPI/history?days=1&resolution=5m"
# Test different time ranges
curl "http://your-server.example.com/weatherAPI/history?days=30&resolution=1d"curl "http://your-server.example.com/weatherAPI/history" | jq '.[0]'Expected: Should show first data point with all required fields
Enable monitoring to see API communication:
idf.py monitorExpected Log Output:
I (12345) WeatherData: Fetching current weather
I (12456) http_client: HTTP GET Status = 200, content_length = 234
I (12567) WeatherData: Current weather updated: Temp=23.5°C
I (45678) WeatherData: Fetching historical data
I (45789) http_client: HTTP GET Status = 200, content_length = 8543
I (45890) WeatherData: Parsed 168 historical data points
Check:
- WiFi Connection: Verify ESP32 is connected to WiFi
- Server URL: Check
WEBSERVER_URLinsecrets.h - Network Connectivity: Ping server from ESP32's network
- Firewall: Ensure server allows connections from ESP32's IP
- API Server: Verify server is running and accessible
Test:
# From a device on same network as ESP32
curl "http://your-server-ip/weatherAPI/current"Symptoms:
E (12345) WeatherData: Failed to parse JSON response
Solutions:
- Validate JSON: Use
jqor online validator - Check Field Names: Ensure exact match (case-sensitive)
- Check Data Types: Numbers as numbers, strings as strings
- Test Response:
curl ... | jq .
Symptoms:
- Charts show gaps
- Fewer than expected data points
Check:
- Array Length: API should return ~168 points for 7 days hourly
- Timestamp Continuity: Check for gaps in timestamps
- Buffer Size: Increase
MAX_BUFFER_SIZEif response is truncated - Memory: Check for heap allocation failures in logs
Test:
# Count data points
curl "http://your-server/weatherAPI/history" | jq 'length'
# Check timestamp range
curl "http://your-server/weatherAPI/history" | jq '[.[0].timestamp, .[-1].timestamp]'Symptoms:
E (45678) http_client: HTTP request timeout
W (45679) WeatherData: Failed to fetch historical data
Solutions:
- Increase Timeout: Edit
HTTP_TIMEOUT_MSinconfig.h - Reduce Data: Use fewer days or higher resolution (1h → 1d)
- Check Network: Measure latency to server
- Optimize API: Add database indexes, caching on server side
Symptoms:
E (12345) http_client: Failed to allocate buffer
E (12346) WeatherData: Out of memory
Solutions:
- Reduce History: Lower
daysparameter - Increase Heap: Check available heap with
esp_get_free_heap_size() - Optimize Parsing: Parse incrementally instead of loading entire response
For production deployments, use HTTPS:
// In secrets.h
#define WEBSERVER_URL "https://your-server.example.com/weatherAPI"Requirements:
- Valid SSL certificate on server
- ESP-IDF certificate bundle enabled (default)
- Server must support TLS 1.2+
If your API requires authentication:
Option 1: Basic Auth
// Add to http_client.c
esp_http_client_set_username(client, "username");
esp_http_client_set_password(client, "password");Option 2: API Key Header
// Add to http_client.c
esp_http_client_set_header(client, "X-API-Key", "your-api-key");Option 3: Bearer Token
esp_http_client_set_header(client, "Authorization", "Bearer your-token");See the included weatherAPI/ directory for a sample PHP-based implementation that:
- Provides
/currentand/historyendpoints - Supports resolution parameters
- Returns properly formatted JSON
- Includes database schema for TimescaleDB
Quick Start:
cd weatherAPI
cp config.php.example config.php
# Edit config.php with your database credentials
# Deploy to web server with PHP 7.4+Use HTTP If-Modified-Since header to reduce bandwidth:
// Only fetch if data has changed since last request
esp_http_client_set_header(client, "If-Modified-Since", last_fetch_time);Benefits:
- Reduced bandwidth usage
- Faster responses (304 Not Modified)
- Lower server load
Enable gzip compression for smaller payloads:
esp_http_client_set_header(client, "Accept-Encoding", "gzip");Benefits:
- ~70% size reduction for JSON
- Faster data transfer
- Requires ESP-IDF gzip support
Fetch only new data points since last update:
GET /history?since=1704312000
Benefits:
- Minimal data transfer
- Faster updates
- Lower memory usage
For a complete reference implementation, see:
- ESP32 Code: main/http_client.c
- Weather Data Manager: gui/WeatherData.cpp
- Sample API Server: weatherAPI/
- Configuration: main/config.h and main/secrets.h.example