Weather Station na API

User avatar
klimasstudio
Posts: 1273
Joined: Wed Aug 28, 2019 9:35 pm
Location: localhost

Post

Cześć chciałbym zrobić stacje pogodową oparą na API OpenWeather. Mam taki kod który juz zczytuje dane. Czy ktoś ogarnięty mógłby wcielić to w suple dodając stronę konfiguracji SSID/HASŁO oraz danych serwera SUPLI i czas odświeżania danych s API jak i długość i szerokość geograficzna.

Code: Select all

#include <Arduino.h>
#include <WiFi.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>
#include <math.h>
#include <WebServer.h>

// ---- WiFi ----
#define WIFI_SSID     "xxx"
#define WIFI_PASSWORD "xxx"

// ---- OpenWeatherMap ----
#define API_KEY  "xxx"
#define LAT      "53.1235"
#define LON      "18.0076"

// ---- Dane pogodowe ----
float temperature = 0;
float humidity    = 0;
float pressure    = 0;
float dew_point   = 0;
float wind_speed  = 0;
float clouds      = 0;
float visibility  = 0;
float rain        = 0;
float snow        = 0;
float uv_index    = 0;

// ---- WebServer ----
WebServer server(80);

void handleRoot() {
  String html = "<!DOCTYPE html><html><head><meta charset='utf-8'>";
  html += "<meta http-equiv='refresh' content='30'>"; // auto-refresh co 30s
  html += "<title>Dane pogodowe ESP32</title>";
  html += "<style>body{font-family:Arial;background:#f2f2f2;text-align:center;} ";
  html += "h1{color:#333;} table{margin:auto;border-collapse:collapse;} ";
  html += "td,th{border:1px solid #888;padding:8px;}</style></head><body>";
  html += "<h1>Aktualne dane pogodowe</h1>";
  html += "<table>";
  html += "<tr><th>Parametr</th><th>Wartość</th></tr>";
  html += "<tr><td>Temperatura</td><td>" + String(temperature, 2) + " °C</td></tr>";
  html += "<tr><td>Wilgotność</td><td>" + String(humidity, 2) + " %</td></tr>";
  html += "<tr><td>Ciśnienie</td><td>" + String(pressure, 2) + " hPa</td></tr>";
  html += "<tr><td>Punkt rosy</td><td>" + String(dew_point, 2) + " °C</td></tr>";
  html += "<tr><td>Wiatr</td><td>" + String(wind_speed, 2) + " m/s</td></tr>";
  html += "<tr><td>Zachmurzenie</td><td>" + String(clouds, 2) + " %</td></tr>";
  html += "<tr><td>Widoczność</td><td>" + String(visibility, 2) + " m</td></tr>";
  html += "<tr><td>Deszcz</td><td>" + String(rain, 2) + " l/m²</td></tr>";
  html += "<tr><td>Śnieg</td><td>" + String(snow, 2) + " l/m²</td></tr>";
  html += "<tr><td>UV index</td><td>" + String(uv_index, 2) + "</td></tr>";
  html += "</table>";
  html += "<p><i>Odświeżanie co 30 sekund</i></p>";
  html += "</body></html>";

  server.send(200, "text/html", html);
}

void fetchWeather() {
  if (WiFi.status() != WL_CONNECTED) {
    Serial.println("[BŁĄD] Brak połączenia z WiFi!");
    return;
  }

  HTTPClient http;
  String url = "https://api.openweathermap.org/data/2.5/weather?lat=" + String(LAT) + "&lon=" + String(LON) + "&appid=" + API_KEY + "&units=metric";
  Serial.println("[INFO] Pobieram dane pogodowe...");
  http.begin(url);
  int httpCode = http.GET();

  if (httpCode == 200) {
    String payload = http.getString();
    DynamicJsonDocument doc(4096);
    if (deserializeJson(doc, payload) == DeserializationError::Ok) {
      temperature = doc["main"]["temp"].as<float>();
      humidity    = doc["main"]["humidity"].as<float>();
      pressure    = doc["main"]["pressure"].as<float>();
      wind_speed  = doc["wind"]["speed"].as<float>();
      clouds      = doc["clouds"]["all"].as<float>();
      visibility  = doc["visibility"].as<float>();

      if (doc.containsKey("rain") && doc["rain"]["1h"])
        rain = doc["rain"]["1h"].as<float>() * 100;
      else
        rain = 0;

      if (doc.containsKey("snow") && doc["snow"]["1h"])
        snow = doc["snow"]["1h"].as<float>() * 100;
      else
        snow = 0;

      dew_point = (237.7 * log(humidity / 100.0) + (17.27 * temperature)) /
                  (17.27 - log(humidity / 100.0));
    }
  }
  http.end();

  // UV index
  url = "https://api.openweathermap.org/data/2.5/uvi?lat=" + String(LAT) + "&lon=" + String(LON) + "&appid=" + API_KEY;
  Serial.println("[INFO] Pobieram UV index...");
  http.begin(url);
  httpCode = http.GET();
  if (httpCode == 200) {
    String payload = http.getString();
    DynamicJsonDocument doc(1024);
    if (deserializeJson(doc, payload) == DeserializationError::Ok) {
      uv_index = doc["value"].as<float>();
    }
  }
  http.end();

  // Debug do konsoli
  Serial.println("=== Dane pogodowe z OpenWeatherMap ===");
  Serial.printf("Temperatura: %.2f °C\n", temperature);
  Serial.printf("Wilgotność: %.2f %%\n", humidity);
  Serial.printf("Ciśnienie: %.2f hPa\n", pressure);
  Serial.printf("Punkt rosy: %.2f °C\n", dew_point);
  Serial.printf("Prędkość wiatru: %.2f m/s\n", wind_speed);
  Serial.printf("Zachmurzenie: %.2f %%\n", clouds);
  Serial.printf("Widoczność: %.2f m\n", visibility);
  Serial.printf("Deszcz: %.2f l/m²\n", rain);
  Serial.printf("Śnieg: %.2f l/m²\n", snow);
  Serial.printf("UV index: %.2f\n", uv_index);
  Serial.println("=====================================");
}

unsigned long lastUpdate = 0;

void setup() {
  Serial.begin(115200);
  delay(2000);
  Serial.println("\n[START] Uruchamianie ESP32...");

  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
  Serial.printf("[INFO] Łączenie z WiFi: %s\n", WIFI_SSID);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("\n[OK] Połączono z WiFi!");
  Serial.print("[INFO] Adres IP: ");
  Serial.println(WiFi.localIP());

  // Serwer WWW
  server.on("/", handleRoot);
  server.begin();
  Serial.println("[OK] Serwer WWW uruchomiony");

  fetchWeather(); // pierwsze pobranie
  lastUpdate = millis();
}

void loop() {
  server.handleClient();
  if (millis() - lastUpdate > 600000) { // co 10 minut
    fetchWeather();
    lastUpdate = millis();
  }
}
image-2025-09-08-134836.png
You do not have the required permissions to view the files attached to this post.
Więc chodź OSUPLUJE Ci dom :mrgreen:

Druk 3D - > https://klimastech.eu.org/druk-3d
User avatar
klew
Posts: 13907
Joined: Thu Jun 27, 2019 12:16 pm
Location: Wrocław
Has thanked: 134 times
Been thanked: 137 times

Post

klimasstudio wrote: Mon Sep 08, 2025 11:56 am
A patrzyłeś w Cloud->Konto->Integracje->Źródła Danych ->Dodaj nowe -> Pogoda
?

To używa Open Weather.
Najlepsze suple dla Twojego domu :mrgreen:
User avatar
klimasstudio
Posts: 1273
Joined: Wed Aug 28, 2019 9:35 pm
Location: localhost

Post

Tam nie ma mojego miasta :D ale nie wiedziałem że takie cudo jest już zintegrowane o.O
Więc chodź OSUPLUJE Ci dom :mrgreen:

Druk 3D - > https://klimastech.eu.org/druk-3d
[email protected]
Posts: 1584
Joined: Mon Feb 06, 2023 8:56 am
Has thanked: 18 times
Been thanked: 26 times

Post

https://github.com/SUPLA/supla-device/b ... rement.ino

zrób tyle kanałów ile masz wartości i zamiast wystawiać na webserver to przypisuj im wartości :)
User avatar
Robert Błaszczak
Posts: 5222
Joined: Sat Dec 22, 2018 8:55 pm
Location: Zielona Góra
Has thanked: 37 times
Been thanked: 27 times

Post

klimasstudio wrote: Mon Sep 08, 2025 12:11 pm Tam nie ma mojego miasta :D ale nie wiedziałem że takie cudo jest już zintegrowane o.O
Ilu użytkowników, tyle lokalizacji localhost, więc może tu być mały problem :lol: :P
Pozdrawiam
Robert Błaszczak


Moja prywatna strona: www.blaszczak.pl
User avatar
klimasstudio
Posts: 1273
Joined: Wed Aug 28, 2019 9:35 pm
Location: localhost

Post

Robert Błaszczak wrote: Mon Sep 08, 2025 12:23 pm Ilu użytkowników, tyle lokalizacji localhost, więc może tu być mały problem :lol: :P
Hahahaha :D nie no Solec Kujawski brak
Więc chodź OSUPLUJE Ci dom :mrgreen:

Druk 3D - > https://klimastech.eu.org/druk-3d
User avatar
Lector
Posts: 2470
Joined: Fri Nov 17, 2017 2:26 pm
Location: Poznań
Has thanked: 13 times
Been thanked: 25 times

Post

klimasstudio wrote: Mon Sep 08, 2025 11:56 am Cześć chciałbym zrobić stacje pogodową oparą na API OpenWeather. Mam taki kod który juz zczytuje dane. Czy ktoś ogarnięty mógłby wcielić to w suple dodając stronę konfiguracji SSID/HASŁO oraz danych serwera SUPLI i czas odświeżania danych s API jak i długość i szerokość geograficzna.

Code: Select all

#include <Arduino.h>
#include <WiFi.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>
#include <math.h>
#include <WebServer.h>

// ---- WiFi ----
#define WIFI_SSID     "xxx"
#define WIFI_PASSWORD "xxx"

// ---- OpenWeatherMap ----
#define API_KEY  "xxx"
#define LAT      "53.1235"
#define LON      "18.0076"

// ---- Dane pogodowe ----
float temperature = 0;
float humidity    = 0;
float pressure    = 0;
float dew_point   = 0;
float wind_speed  = 0;
float clouds      = 0;
float visibility  = 0;
float rain        = 0;
float snow        = 0;
float uv_index    = 0;

// ---- WebServer ----
WebServer server(80);

void handleRoot() {
  String html = "<!DOCTYPE html><html><head><meta charset='utf-8'>";
  html += "<meta http-equiv='refresh' content='30'>"; // auto-refresh co 30s
  html += "<title>Dane pogodowe ESP32</title>";
  html += "<style>body{font-family:Arial;background:#f2f2f2;text-align:center;} ";
  html += "h1{color:#333;} table{margin:auto;border-collapse:collapse;} ";
  html += "td,th{border:1px solid #888;padding:8px;}</style></head><body>";
  html += "<h1>Aktualne dane pogodowe</h1>";
  html += "<table>";
  html += "<tr><th>Parametr</th><th>Wartość</th></tr>";
  html += "<tr><td>Temperatura</td><td>" + String(temperature, 2) + " °C</td></tr>";
  html += "<tr><td>Wilgotność</td><td>" + String(humidity, 2) + " %</td></tr>";
  html += "<tr><td>Ciśnienie</td><td>" + String(pressure, 2) + " hPa</td></tr>";
  html += "<tr><td>Punkt rosy</td><td>" + String(dew_point, 2) + " °C</td></tr>";
  html += "<tr><td>Wiatr</td><td>" + String(wind_speed, 2) + " m/s</td></tr>";
  html += "<tr><td>Zachmurzenie</td><td>" + String(clouds, 2) + " %</td></tr>";
  html += "<tr><td>Widoczność</td><td>" + String(visibility, 2) + " m</td></tr>";
  html += "<tr><td>Deszcz</td><td>" + String(rain, 2) + " l/m²</td></tr>";
  html += "<tr><td>Śnieg</td><td>" + String(snow, 2) + " l/m²</td></tr>";
  html += "<tr><td>UV index</td><td>" + String(uv_index, 2) + "</td></tr>";
  html += "</table>";
  html += "<p><i>Odświeżanie co 30 sekund</i></p>";
  html += "</body></html>";

  server.send(200, "text/html", html);
}

void fetchWeather() {
  if (WiFi.status() != WL_CONNECTED) {
    Serial.println("[BŁĄD] Brak połączenia z WiFi!");
    return;
  }

  HTTPClient http;
  String url = "https://api.openweathermap.org/data/2.5/weather?lat=" + String(LAT) + "&lon=" + String(LON) + "&appid=" + API_KEY + "&units=metric";
  Serial.println("[INFO] Pobieram dane pogodowe...");
  http.begin(url);
  int httpCode = http.GET();

  if (httpCode == 200) {
    String payload = http.getString();
    DynamicJsonDocument doc(4096);
    if (deserializeJson(doc, payload) == DeserializationError::Ok) {
      temperature = doc["main"]["temp"].as<float>();
      humidity    = doc["main"]["humidity"].as<float>();
      pressure    = doc["main"]["pressure"].as<float>();
      wind_speed  = doc["wind"]["speed"].as<float>();
      clouds      = doc["clouds"]["all"].as<float>();
      visibility  = doc["visibility"].as<float>();

      if (doc.containsKey("rain") && doc["rain"]["1h"])
        rain = doc["rain"]["1h"].as<float>() * 100;
      else
        rain = 0;

      if (doc.containsKey("snow") && doc["snow"]["1h"])
        snow = doc["snow"]["1h"].as<float>() * 100;
      else
        snow = 0;

      dew_point = (237.7 * log(humidity / 100.0) + (17.27 * temperature)) /
                  (17.27 - log(humidity / 100.0));
    }
  }
  http.end();

  // UV index
  url = "https://api.openweathermap.org/data/2.5/uvi?lat=" + String(LAT) + "&lon=" + String(LON) + "&appid=" + API_KEY;
  Serial.println("[INFO] Pobieram UV index...");
  http.begin(url);
  httpCode = http.GET();
  if (httpCode == 200) {
    String payload = http.getString();
    DynamicJsonDocument doc(1024);
    if (deserializeJson(doc, payload) == DeserializationError::Ok) {
      uv_index = doc["value"].as<float>();
    }
  }
  http.end();

  // Debug do konsoli
  Serial.println("=== Dane pogodowe z OpenWeatherMap ===");
  Serial.printf("Temperatura: %.2f °C\n", temperature);
  Serial.printf("Wilgotność: %.2f %%\n", humidity);
  Serial.printf("Ciśnienie: %.2f hPa\n", pressure);
  Serial.printf("Punkt rosy: %.2f °C\n", dew_point);
  Serial.printf("Prędkość wiatru: %.2f m/s\n", wind_speed);
  Serial.printf("Zachmurzenie: %.2f %%\n", clouds);
  Serial.printf("Widoczność: %.2f m\n", visibility);
  Serial.printf("Deszcz: %.2f l/m²\n", rain);
  Serial.printf("Śnieg: %.2f l/m²\n", snow);
  Serial.printf("UV index: %.2f\n", uv_index);
  Serial.println("=====================================");
}

unsigned long lastUpdate = 0;

void setup() {
  Serial.begin(115200);
  delay(2000);
  Serial.println("\n[START] Uruchamianie ESP32...");

  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
  Serial.printf("[INFO] Łączenie z WiFi: %s\n", WIFI_SSID);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("\n[OK] Połączono z WiFi!");
  Serial.print("[INFO] Adres IP: ");
  Serial.println(WiFi.localIP());

  // Serwer WWW
  server.on("/", handleRoot);
  server.begin();
  Serial.println("[OK] Serwer WWW uruchomiony");

  fetchWeather(); // pierwsze pobranie
  lastUpdate = millis();
}

void loop() {
  server.handleClient();
  if (millis() - lastUpdate > 600000) { // co 10 minut
    fetchWeather();
    lastUpdate = millis();
  }
}
image-2025-09-08-134836.png
https://chatgpt.com/
Ci pomoże, daj mu jakiś przykład z Supla Device i aby ci przerobił.
Bawiłem się tak do systemu podlewania i coś mu nawet wychodziło.
Niespełniony automatyk. :mrgreen:
https://3d-lamp.photos/
https://pool.lector.top/
User avatar
klimasstudio
Posts: 1273
Joined: Wed Aug 28, 2019 9:35 pm
Location: localhost

Post

Próbowałem ale jakoś mu nie poszło wymieszał wersje 1.0 z 2.0 i nic nie byl w stanie wykompilowac co by sie uruchomiło.
Więc chodź OSUPLUJE Ci dom :mrgreen:

Druk 3D - > https://klimastech.eu.org/druk-3d
User avatar
klimasstudio
Posts: 1273
Joined: Wed Aug 28, 2019 9:35 pm
Location: localhost

Post

Jak dane odczytać wiem ale nie mam pojecia aby zrobić szkielet do wysylania danych do SUPLI. Nie bardzo mi to idzie ;/
Więc chodź OSUPLUJE Ci dom :mrgreen:

Druk 3D - > https://klimastech.eu.org/druk-3d
User avatar
veeroos
Posts: 1080
Joined: Sun Mar 20, 2022 9:30 am
Location: Głogów
Has thanked: 1 time
Been thanked: 9 times

Post

Hej, spójrz jak ja robię parametry do webserwera dla bramki Airly , może to Cię naprowadzi na rozwiązanie, jak nie to pisz śmiało przerobię Twój program tak aby wszystko chodziło 😉
Deklaruję zmienne:

Code: Select all

const char PARAM1[] = "param1";
const char PARAM2[] = "param2";
const char PARAM3[] = "param3";
const char PARAM4[] = "param4";

char lat[40]={};
char lon[40]={};
char distance[40]={};
char apiKey[40]={};
Następnie w Setupie robimy obsługę tych danych i tworzymy okna w webserwerze żeby móc te dane wpisywać.

Code: Select all

  Supla::Storage::Init();
  if (Supla::Storage::ConfigInstance()->getString(PARAM1, lat, 40)) {
    SUPLA_LOG_DEBUG("# Param[%s]: %s", PARAM1, lat);
  } else {
    Supla::Storage::ConfigInstance()->setString(PARAM1, "51.00000");
  }
  if (Supla::Storage::ConfigInstance()->getString(PARAM2, lon, 40)) {
    SUPLA_LOG_DEBUG("# Param[%s]: %s", PARAM2, lon);
  } else {
    Supla::Storage::ConfigInstance()->setString(PARAM2, "16.00000");
  }
  if (Supla::Storage::ConfigInstance()->getString(PARAM3, distance, 40)) {
    SUPLA_LOG_DEBUG("# Param[%s]: %s", PARAM3, distance);
  } else {
    Supla::Storage::ConfigInstance()->setString(PARAM3, "5");
  }
  if (Supla::Storage::ConfigInstance()->getString(PARAM4, apiKey, 40)) {
    SUPLA_LOG_DEBUG("# Param[%s]: %s", PARAM4, apiKey);
  } else {
    Supla::Storage::ConfigInstance()->setString(PARAM4, "abcdefghijklmnoprstuwyz");
  }
    new Supla::Html::CustomTextParameter(PARAM1, "Szerokość geograficzna", 40);
  new Supla::Html::CustomTextParameter(PARAM2, "Długość geograficzna", 40);
  new Supla::Html::CustomTextParameter(PARAM3, "Promień wyszukiwania stacji (km)", 40);
  new Supla::Html::CustomTextParameter(PARAM4, "ApiKey", 40);
  
A później już te dane wykorzystujesz w programie odczytu.
Oczywiście są to wycinki z programu, ale jak użyjesz je w podobny sposób jak ja to wtedy powinno chodzić
Zamel Mew-01, Zamel PEW-01, Zamel SBW-01, Zamel THW-01, Zamel SRW-01, Zamel mSLW-02, Auraton BOX + Indor Sensor, Airly Gate By Veeroos, Zigbee to Supla Gateway + sensors, Zamel SGW-01 and more

https://github.com/v33r005

Return to “Projekty użytkowników”