v.0.3.0 Library WeatherData

This commit is contained in:
tiijay
2025-11-10 12:09:38 +01:00
parent dce7117267
commit 4c8b5c952b
6 changed files with 343 additions and 0 deletions

View 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"
}

View 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;
}

View 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

View 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
View 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
View 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