v.0.3.0 Library WeatherData
This commit is contained in:
7
lib/WeatherData/library.json
Normal file
7
lib/WeatherData/library.json
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"name": "BlinkLed",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "A simple LED control library with internal LED helper.",
|
||||||
|
"authors": [{ "name": "TiiJay14" }],
|
||||||
|
"frameworks": "arduino"
|
||||||
|
}
|
||||||
187
lib/WeatherData/src/WeatherFetcher.cpp
Normal file
187
lib/WeatherData/src/WeatherFetcher.cpp
Normal file
@@ -0,0 +1,187 @@
|
|||||||
|
#include "WeatherFetcher.h"
|
||||||
|
#include <WiFi.h>
|
||||||
|
#include <HTTPClient.h>
|
||||||
|
#include <ArduinoJson.h>
|
||||||
|
|
||||||
|
#include <ColorSerial.h>
|
||||||
|
|
||||||
|
WeatherFetcher::WeatherFetcher(const char *api_key) : API_KEY(api_key) {}
|
||||||
|
|
||||||
|
bool WeatherFetcher::connectToWiFi(const char *ssid, const char *password)
|
||||||
|
{
|
||||||
|
ColorSerial::info("Verbinde mit WiFi: ");
|
||||||
|
ColorSerial::info(ssid);
|
||||||
|
|
||||||
|
WiFi.begin(ssid, password);
|
||||||
|
|
||||||
|
int attempts = 0;
|
||||||
|
while (WiFi.status() != WL_CONNECTED && attempts < 20)
|
||||||
|
{
|
||||||
|
delay(1000);
|
||||||
|
ColorSerial::info(".");
|
||||||
|
attempts++;
|
||||||
|
}
|
||||||
|
|
||||||
|
ColorSerial::wifiStatus();
|
||||||
|
|
||||||
|
return WiFi.status() == WL_CONNECTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
Weather WeatherFetcher::actual_weather(const char *city, const char *lang, bool test_mode)
|
||||||
|
{
|
||||||
|
if (test_mode)
|
||||||
|
{
|
||||||
|
return create_test_weather();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (WiFi.status() != WL_CONNECTED)
|
||||||
|
{
|
||||||
|
Serial.println("Keine WiFi Verbindung!");
|
||||||
|
return weather;
|
||||||
|
}
|
||||||
|
|
||||||
|
String weather_url =
|
||||||
|
"https://api.weatherapi.com/v1/current.json?key=" + String(API_KEY) +
|
||||||
|
"&q=" + String(city) + "&aqi=yes&lang=" + String(lang);
|
||||||
|
|
||||||
|
Serial.println("Hole Wetterdaten von: " + weather_url);
|
||||||
|
|
||||||
|
String json_data = fetch_from_url(weather_url);
|
||||||
|
|
||||||
|
if (!json_data.isEmpty())
|
||||||
|
{
|
||||||
|
weather = parse_weather_json(json_data);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Serial.println("Fehler beim Abrufen der Wetterdaten!");
|
||||||
|
}
|
||||||
|
|
||||||
|
return weather;
|
||||||
|
}
|
||||||
|
|
||||||
|
String WeatherFetcher::fetch_from_url(const String &url)
|
||||||
|
{
|
||||||
|
HTTPClient http;
|
||||||
|
String payload = "";
|
||||||
|
|
||||||
|
http.begin(url);
|
||||||
|
http.setTimeout(10000);
|
||||||
|
|
||||||
|
int httpCode = http.GET();
|
||||||
|
|
||||||
|
if (httpCode == HTTP_CODE_OK)
|
||||||
|
{
|
||||||
|
payload = http.getString();
|
||||||
|
Serial.println("Daten erfolgreich empfangen");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Serial.printf("HTTP Fehler: %d\n", httpCode);
|
||||||
|
Serial.println(http.errorToString(httpCode));
|
||||||
|
}
|
||||||
|
|
||||||
|
http.end();
|
||||||
|
return payload;
|
||||||
|
}
|
||||||
|
|
||||||
|
Weather WeatherFetcher::parse_weather_json(const String &json_data)
|
||||||
|
{
|
||||||
|
Weather weather;
|
||||||
|
|
||||||
|
const size_t capacity = JSON_OBJECT_SIZE(20) + JSON_OBJECT_SIZE(10) + JSON_OBJECT_SIZE(15) + 2048;
|
||||||
|
DynamicJsonDocument doc(capacity);
|
||||||
|
|
||||||
|
DeserializationError error = deserializeJson(doc, json_data);
|
||||||
|
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
Serial.print("JSON Parsing fehlgeschlagen: ");
|
||||||
|
Serial.println(error.c_str());
|
||||||
|
return weather;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Location Daten parsen - jetzt direkt mit Arduino String
|
||||||
|
if (doc.containsKey("location"))
|
||||||
|
{
|
||||||
|
JsonObject location = doc["location"];
|
||||||
|
weather.location.name = location["name"].as<String>();
|
||||||
|
weather.location.region = location["region"].as<String>();
|
||||||
|
weather.location.country = location["country"].as<String>();
|
||||||
|
weather.location.localtime = location["localtime"].as<String>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Current Condition Daten parsen
|
||||||
|
if (doc.containsKey("current"))
|
||||||
|
{
|
||||||
|
JsonObject current = doc["current"];
|
||||||
|
weather.current.last_updated = current["last_updated"].as<String>();
|
||||||
|
weather.current.temp_c = current["temp_c"].as<float>();
|
||||||
|
weather.current.is_day = current["is_day"].as<int>();
|
||||||
|
weather.current.wind_kph = current["wind_kph"].as<float>();
|
||||||
|
weather.current.wind_dir = current["wind_dir"].as<String>();
|
||||||
|
weather.current.pressure_mb = current["pressure_mb"].as<float>();
|
||||||
|
weather.current.humidity = current["humidity"].as<int>();
|
||||||
|
weather.current.cloud = current["cloud"].as<int>();
|
||||||
|
weather.current.feelslike_c = current["feelslike_c"].as<float>();
|
||||||
|
|
||||||
|
// Condition Daten parsen
|
||||||
|
if (current.containsKey("condition"))
|
||||||
|
{
|
||||||
|
JsonObject condition = current["condition"];
|
||||||
|
weather.current.condition.text = condition["text"].as<String>();
|
||||||
|
weather.current.condition.icon = condition["icon"].as<String>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Air Quality Daten parsen
|
||||||
|
if (current.containsKey("air_quality"))
|
||||||
|
{
|
||||||
|
JsonObject air_quality = current["air_quality"];
|
||||||
|
weather.current.air_quality.co = air_quality["co"].as<float>();
|
||||||
|
weather.current.air_quality.no2 = air_quality["no2"].as<float>();
|
||||||
|
weather.current.air_quality.o3 = air_quality["o3"].as<float>();
|
||||||
|
weather.current.air_quality.so2 = air_quality["so2"].as<float>();
|
||||||
|
weather.current.air_quality.pm2_5 = air_quality["pm2_5"].as<float>();
|
||||||
|
weather.current.air_quality.pm10 = air_quality["pm10"].as<float>();
|
||||||
|
weather.current.air_quality.us_epa_index = air_quality["us-epa-index"].as<int>();
|
||||||
|
weather.current.air_quality.gb_defra_index = air_quality["gb-defra-index"].as<int>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Serial.println("Wetterdaten erfolgreich geparsed");
|
||||||
|
return weather;
|
||||||
|
}
|
||||||
|
|
||||||
|
Weather WeatherFetcher::create_test_weather()
|
||||||
|
{
|
||||||
|
Weather test_weather;
|
||||||
|
|
||||||
|
test_weather.location.name = "Grosshansdorf";
|
||||||
|
test_weather.location.region = "Schleswig-Holstein";
|
||||||
|
test_weather.location.country = "Germany";
|
||||||
|
test_weather.location.localtime = "2023-10-01 12:30";
|
||||||
|
|
||||||
|
test_weather.current.last_updated = "2023-10-01 12:30";
|
||||||
|
test_weather.current.temp_c = 15.5;
|
||||||
|
test_weather.current.is_day = 1;
|
||||||
|
test_weather.current.condition.text = "Sonnig";
|
||||||
|
test_weather.current.condition.icon = "//cdn.weatherapi.com/weather/64x64/day/113.png";
|
||||||
|
test_weather.current.wind_kph = 12.3;
|
||||||
|
test_weather.current.wind_dir = "NW";
|
||||||
|
test_weather.current.pressure_mb = 1013.0;
|
||||||
|
test_weather.current.humidity = 65;
|
||||||
|
test_weather.current.cloud = 10;
|
||||||
|
test_weather.current.feelslike_c = 15.2;
|
||||||
|
|
||||||
|
test_weather.current.air_quality.co = 250.0;
|
||||||
|
test_weather.current.air_quality.no2 = 12.5;
|
||||||
|
test_weather.current.air_quality.o3 = 45.2;
|
||||||
|
test_weather.current.air_quality.so2 = 2.1;
|
||||||
|
test_weather.current.air_quality.pm2_5 = 8.5;
|
||||||
|
test_weather.current.air_quality.pm10 = 12.3;
|
||||||
|
test_weather.current.air_quality.us_epa_index = 1;
|
||||||
|
test_weather.current.air_quality.gb_defra_index = 2;
|
||||||
|
|
||||||
|
Serial.println("Test-Wetterdaten generiert");
|
||||||
|
return test_weather;
|
||||||
|
}
|
||||||
27
lib/WeatherData/src/WeatherFetcher.h
Normal file
27
lib/WeatherData/src/WeatherFetcher.h
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
#ifndef WEATHER_FETCHER_H
|
||||||
|
#define WEATHER_FETCHER_H
|
||||||
|
|
||||||
|
#include "WeatherStructs.h"
|
||||||
|
#include <WiFi.h>
|
||||||
|
#include <ArduinoJson.h>
|
||||||
|
|
||||||
|
class WeatherFetcher
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
Weather weather;
|
||||||
|
const char *API_KEY;
|
||||||
|
|
||||||
|
public:
|
||||||
|
WeatherFetcher(const char *api_key);
|
||||||
|
bool connectToWiFi(const char *ssid, const char *password);
|
||||||
|
Weather actual_weather(const char *city = "grosshansdorf",
|
||||||
|
const char *lang = "de",
|
||||||
|
bool test_mode = false);
|
||||||
|
|
||||||
|
private:
|
||||||
|
String fetch_from_url(const String &url);
|
||||||
|
Weather parse_weather_json(const String &json_data);
|
||||||
|
Weather create_test_weather();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
53
lib/WeatherData/src/WeatherStructs.h
Normal file
53
lib/WeatherData/src/WeatherStructs.h
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
#ifndef WEATHERSTRUCTS_H
|
||||||
|
#define WEATHERSTRUCTS_H
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
|
struct Location
|
||||||
|
{
|
||||||
|
String name = "";
|
||||||
|
String region = "";
|
||||||
|
String country = "";
|
||||||
|
String localtime = "";
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Condition
|
||||||
|
{
|
||||||
|
std::optional<String> text;
|
||||||
|
std::optional<String> icon;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AirQuality
|
||||||
|
{
|
||||||
|
double co = 0.0;
|
||||||
|
double no2 = 0.0;
|
||||||
|
double o3 = 0.0;
|
||||||
|
double so2 = 0.0;
|
||||||
|
double pm2_5 = 0.0;
|
||||||
|
double pm10 = 0.0;
|
||||||
|
int us_epa_index = 0;
|
||||||
|
int gb_defra_index = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CurrentCondition
|
||||||
|
{
|
||||||
|
String last_updated;
|
||||||
|
double temp_c = 0.0;
|
||||||
|
int is_day = 0;
|
||||||
|
Condition condition;
|
||||||
|
double wind_kph = 0.0;
|
||||||
|
String wind_dir;
|
||||||
|
double pressure_mb = 0.0;
|
||||||
|
int humidity = 0;
|
||||||
|
int cloud = 0;
|
||||||
|
double feelslike_c = 0.0;
|
||||||
|
AirQuality air_quality;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Weather
|
||||||
|
{
|
||||||
|
Location location;
|
||||||
|
CurrentCondition current;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
57
restapi/mock-weather.json
Normal file
57
restapi/mock-weather.json
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
{
|
||||||
|
"location": {
|
||||||
|
"name": "Grosshansdorf",
|
||||||
|
"region": "Schleswig-Holstein",
|
||||||
|
"country": "Germany",
|
||||||
|
"lat": 53.6667,
|
||||||
|
"lon": 10.2833,
|
||||||
|
"tz_id": "Europe/Berlin",
|
||||||
|
"localtime_epoch": 1761383733,
|
||||||
|
"localtime": "2025-10-25 11:15"
|
||||||
|
},
|
||||||
|
"current": {
|
||||||
|
"last_updated_epoch": 1761383700,
|
||||||
|
"last_updated": "2025-10-25 11:15",
|
||||||
|
"temp_c": 10.2,
|
||||||
|
"temp_f": 50.4,
|
||||||
|
"is_day": 1,
|
||||||
|
"condition": {
|
||||||
|
"text": "Overcast",
|
||||||
|
"icon": "//cdn.weatherapi.com/weather/64x64/day/122.png",
|
||||||
|
"code": 1009
|
||||||
|
},
|
||||||
|
"wind_mph": 17.7,
|
||||||
|
"wind_kph": 28.4,
|
||||||
|
"wind_degree": 208,
|
||||||
|
"wind_dir": "SSW",
|
||||||
|
"pressure_mb": 991.0,
|
||||||
|
"pressure_in": 29.26,
|
||||||
|
"precip_mm": 0.03,
|
||||||
|
"precip_in": 0.0,
|
||||||
|
"humidity": 82,
|
||||||
|
"cloud": 100,
|
||||||
|
"feelslike_c": 6.9,
|
||||||
|
"feelslike_f": 44.5,
|
||||||
|
"windchill_c": 5.4,
|
||||||
|
"windchill_f": 41.8,
|
||||||
|
"heatindex_c": 9.0,
|
||||||
|
"heatindex_f": 48.3,
|
||||||
|
"dewpoint_c": 6.3,
|
||||||
|
"dewpoint_f": 43.4,
|
||||||
|
"vis_km": 10.0,
|
||||||
|
"vis_miles": 6.0,
|
||||||
|
"uv": 0.1,
|
||||||
|
"gust_mph": 25.3,
|
||||||
|
"gust_kph": 40.7,
|
||||||
|
"air_quality": {
|
||||||
|
"co": 155.678,
|
||||||
|
"no2": 9.678,
|
||||||
|
"o3": 45.0,
|
||||||
|
"so2": 2.078,
|
||||||
|
"pm2_5": 4.678,
|
||||||
|
"pm10": 6.178,
|
||||||
|
"us-epa-index": 1,
|
||||||
|
"gb-defra-index": 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
12
restapi/weather.http
Normal file
12
restapi/weather.http
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
@city = "grosshansdorf"
|
||||||
|
@lang = en
|
||||||
|
@forecast_days = 3
|
||||||
|
# could be 60(mins) or 24(day)
|
||||||
|
@time_period_forecast = 60
|
||||||
|
@key = 3545ce42d0ba436e8dc164532250410
|
||||||
|
|
||||||
|
### aktuelles Wetter
|
||||||
|
GET https://api.weatherapi.com/v1/current.json?key={{key}}&q={{city}}&aqi=yes&lang={{lang}}
|
||||||
|
|
||||||
|
### Vorhersage für n Tage (max 3 Tage for Free-Plan!)
|
||||||
|
GET https://api.weatherapi.com/v1/forecast.json?q={{city}}&days={{forecast_days}}&tp={{time_period_forecast}}&key={{key}}&lang=de
|
||||||
Reference in New Issue
Block a user