commit 0b48b6044e26f55bdf6955164c77db6f713da7ee Author: Tomislav Kopić Date: Wed Feb 7 20:06:07 2024 +0100 Migrate diff --git a/Bitmaps/Clear.png b/Bitmaps/Clear.png new file mode 100644 index 0000000..4c25681 Binary files /dev/null and b/Bitmaps/Clear.png differ diff --git a/Bitmaps/Drizzle.png b/Bitmaps/Drizzle.png new file mode 100644 index 0000000..8eabb1e Binary files /dev/null and b/Bitmaps/Drizzle.png differ diff --git a/Bitmaps/Fog.png b/Bitmaps/Fog.png new file mode 100644 index 0000000..e729881 Binary files /dev/null and b/Bitmaps/Fog.png differ diff --git a/Bitmaps/Hail.png b/Bitmaps/Hail.png new file mode 100644 index 0000000..dc48ca5 Binary files /dev/null and b/Bitmaps/Hail.png differ diff --git a/Bitmaps/Rain.png b/Bitmaps/Rain.png new file mode 100644 index 0000000..0429782 Binary files /dev/null and b/Bitmaps/Rain.png differ diff --git a/Bitmaps/Snow.png b/Bitmaps/Snow.png new file mode 100644 index 0000000..c23f90a Binary files /dev/null and b/Bitmaps/Snow.png differ diff --git a/Bitmaps/Thunderstorms.png b/Bitmaps/Thunderstorms.png new file mode 100644 index 0000000..188741e Binary files /dev/null and b/Bitmaps/Thunderstorms.png differ diff --git a/D1_mini_weather_station.ino b/D1_mini_weather_station.ino new file mode 100644 index 0000000..6368dce --- /dev/null +++ b/D1_mini_weather_station.ino @@ -0,0 +1,207 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "bitmaps.h" +#define SCREEN_WIDTH 128 +#define SCREEN_HEIGHT 64 +#define OLED_RESET -1 +Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); +WiFiClient client; + +// set Wi-Fi SSID and password +const char *ssid = "wifinetwork"; +const char *password = "12345678"; + +// Define NTP Client to get time +WiFiUDP ntpUDP; +NTPClient timeClient(ntpUDP, "pool.ntp.org"); + +// set location and API key +const String Location = "Osijek"; +const String API_Key = "someapikey"; +int icon = 0; + +void capitalizeFirstLetter(char* str) { + if (str != nullptr && *str != '\0') { + // Create a copy of the string + char temp[48]; + strcpy(temp, str); + + // Capitalize the first letter + temp[0] = toupper(temp[0]); + + // Copy the modified string back to the original pointer + strcpy(str, temp); + } +} + +void setup(void) +{ + display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // initialize with the I2C addr 0x3D (for the 128x64) + delay(1000); + display.clearDisplay(); // clear the display buffer + display.display(); + display.setTextColor(WHITE, BLACK); + display.setTextSize(1); + WiFi.mode(WIFI_STA); + WiFi.disconnect(); + WiFi.begin(ssid, password); + display.setCursor(0, 0); + display.print("Connecting"); + display.display(); + int cnt = 0; + while ( WiFi.status() != WL_CONNECTED ) + { + if (cnt == 3) { + cnt = 0; + display.clearDisplay(); + display.setCursor(0, 0); + display.print("Connecting"); + display.display(); + } else { + display.print("."); + display.display(); + cnt++; + } + delay(1000); + } + WiFi.setAutoReconnect(true); + WiFi.persistent(true); + display.print("\nconnected"); + display.display(); + timeClient.begin(); + delay(500); + timeClient.setTimeOffset(3600); +} + +void loop() +{ + if (WiFi.status() == WL_CONNECTED) { + + timeClient.update(); + // PowerSave + int currentHour = timeClient.getHours(); + if (currentHour >= 23 || currentHour < 6) { + display.clearDisplay(); + display.display(); + display.ssd1306_command(SSD1306_DISPLAYOFF); + delay(300000); + return; + } + else { + display.ssd1306_command(SSD1306_DISPLAYON); + } + //Get a time structure + time_t epochTime = timeClient.getEpochTime(); + struct tm *ptm = gmtime ((time_t *)&epochTime); + int currentDay = ptm->tm_mday; + int currentMonth = ptm->tm_mon + 1; + int currentYear = ptm->tm_year + 1900; + HTTPClient http; //Declare an object of class HTTPClient + + // specify request destination + http.begin(client, "http://api.openweathermap.org/data/2.5/weather?q=" + Location + "&APPID=" + API_Key); // !! + int httpCode = http.GET(); // send the request + if (httpCode > 0) { + String payload = http.getString(); //Get the request response payload + + DynamicJsonBuffer jsonBuffer(1024); + + // Parse JSON object + JsonObject& root = jsonBuffer.parseObject(payload); + if (!root.success()) { + return; + } + http.end(); //Close connection + const char* state = root["weather"][0]["description"]; // get status as string + capitalizeFirstLetter(const_cast(state)); // Capitalize the first letter + float temp = (float)(root["main"]["temp"]) - 273.15; // get temperature in °C + int humidity = root["main"]["humidity"]; // get humidity in % + float pressure = (float)(root["main"]["pressure"]) / 1000; // get pressure in bar + float wind_speed = root["wind"]["speed"]; // get wind speed in m/s + int statusSize = 2; + if (strlen(state) > 12) { + statusSize = 1; + } + // print data + display.clearDisplay(); // clear the display buffer + display.setTextSize(1); + display.setCursor(0, 0); + display.printf("%d-%d-%d\r\n", currentYear, currentMonth, currentDay); + display.setCursor(0, 9); + display.printf("%s",Location); + display.setTextSize(statusSize); + display.setCursor(0, 21); + display.printf("%s\r\n", state); + display.setCursor(0, 39); + display.setTextSize(1); + display.printf(" %5.2f C %d%%\r\n", temp, humidity); + display.drawRect(43, 39, 3, 3, WHITE); // put degree symbol ( ° ) + display.setCursor(0, 52); + display.printf(" %.3fbar %.1fm/s \r\n", pressure, wind_speed); + display.drawLine(0, 18, 127, 18, 1); + display.drawLine(65, 18, 65, 0, 1); + display.drawBitmap(0, 38, temperature_icon, 10, 10, WHITE); + display.drawBitmap(74, 38, humidity_icon, 10, 10, WHITE); + display.drawBitmap(0, 51, pressure_icon, 10, 10, WHITE); + display.drawBitmap(74, 51, wind_icon, 10, 10, WHITE); + display.display(); + } + + // specify request destination + http.begin(client, "http://api.openweathermap.org/data/2.5/forecast?q=" + Location + "&APPID=" + API_Key + "&cnt=3"); // !! + httpCode = http.GET(); // send the request + if (httpCode > 0) { + String payload = http.getString(); //Get the request response payload + DynamicJsonBuffer jsonBuffer(1024); + + // Parse JSON object + JsonObject& forecast = jsonBuffer.parseObject(payload); + if (!forecast.success()) { + return; + } + http.end(); //Close connection + + // State id info + // 200-232 Thunderstorm + // 300-321 Drizzle + // 500-531 Rain + // 600-622 Snow + // 701-781 Mist + // 800 Clear + // 801-804 Clouds + int pos = 69; + for (int day = 0; day <= 2; day++) { + int state = forecast["list"][day]["weather"][0]["id"]; // get state id + // Display bitmap based on state_id + if (state >= 200 && state <= 232) { + icon = 6; // Thunderstorm + } else if (state >= 300 && state <= 321) { + icon = 5; // Drizzle + } else if (state >= 500 && state <= 531) { + icon = 3; // Rain + } else if (state >= 600 && state <= 622) { + icon = 4; // Snow + } else if (state >= 701 && state <= 781) { + icon = 2; // Mist + } else if (state == 800) { + icon = 0; // Clear + } else if (state >= 801 && state <= 804) { + icon = 1; // Clouds + } else { + // Handle unknown state_id + icon = 0; // Default to Clear icon + } + display.drawBitmap(pos, 0, bitmap_icons[icon], 16, 16, WHITE); + pos = pos + 20; + display.display(); + } + } + } + delay(1800000); +} diff --git a/bitmaps.h b/bitmaps.h new file mode 100644 index 0000000..835215b --- /dev/null +++ b/bitmaps.h @@ -0,0 +1,71 @@ +// 'clear', 16x16px +const unsigned char bitmap_clear [] PROGMEM = { + 0x01, 0x80, 0x01, 0x80, 0x31, 0x8c, 0x38, 0x1c, 0x1f, 0xf8, 0x0f, 0xf0, 0x0c, 0x30, 0xec, 0x37, + 0xec, 0x37, 0x0c, 0x30, 0x0f, 0xf0, 0x1f, 0xf8, 0x38, 0x1c, 0x31, 0x8c, 0x01, 0x80, 0x01, 0x80 +}; + +// 'cloudy', 16x16px +const unsigned char bitmap_cloudy [] PROGMEM = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xf0, 0x03, 0xf8, 0x0f, 0x9e, 0x1f, 0xcf, 0x78, 0xf3, + 0xf0, 0x7b, 0xc0, 0x1f, 0xc0, 0x1f, 0xff, 0xf8, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; +// 'fog', 16x16px +const unsigned char bitmap_fog [] PROGMEM = { + 0x00, 0x00, 0x78, 0x1e, 0xff, 0xff, 0xef, 0xf7, 0x00, 0x00, 0xfe, 0x7f, 0xff, 0xff, 0x03, 0xc0, + 0x7c, 0x3e, 0xff, 0xff, 0xcf, 0xf3, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x01, 0x80, 0x00, 0x00 +}; + +// 'rain', 16x16px +const unsigned char bitmap_rain [] PROGMEM = { + 0x0f, 0x80, 0x1f, 0xc0, 0x38, 0xf8, 0x70, 0x7c, 0xf0, 0x0c, 0xe0, 0x0f, 0xc0, 0x07, 0xc0, 0x03, + 0xc0, 0x03, 0xff, 0xff, 0x7f, 0xfe, 0x66, 0x33, 0xe6, 0x73, 0xff, 0xff, 0xff, 0xfe, 0x73, 0x38 +}; + +// 'snow', 16x16px +const unsigned char bitmap_snow [] PROGMEM = { + 0x01, 0x80, 0x07, 0xe0, 0x1f, 0xf8, 0x7b, 0xde, 0x79, 0x9e, 0x7d, 0xbe, 0x7f, 0xfe, 0x67, 0xe6, + 0x67, 0xe6, 0x7f, 0xfe, 0x7d, 0xbe, 0x79, 0x9e, 0x7b, 0xde, 0x1f, 0xf8, 0x07, 0xe0, 0x01, 0x80 +}; + +// 'thunderstorm', 16x16px +const unsigned char bitmap_thunderstorm [] PROGMEM = { + 0x07, 0xf0, 0x06, 0x60, 0x0e, 0x60, 0x0c, 0xc0, 0x0c, 0xf8, 0x18, 0xfc, 0x18, 0x18, 0x38, 0x38, + 0x3f, 0xf0, 0x1f, 0xe0, 0x03, 0xe0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0x80, 0x07, 0x00, 0x07, 0x00 +}; + +// 'drizzle', 16x16px +const unsigned char bitmap_drizzle [] PROGMEM = { + 0x00, 0x00, 0x06, 0x00, 0x36, 0xc0, 0x3f, 0x80, 0x1f, 0xf0, 0x7b, 0xb8, 0x1e, 0x18, 0x18, 0x0e, + 0x18, 0x06, 0x19, 0x32, 0x0f, 0xfe, 0x07, 0xfc, 0x01, 0xf0, 0x03, 0xf0, 0x00, 0xc0, 0x00, 0x00 +}; + +// Array of all bitmaps for convenience +const unsigned char* bitmap_icons[7] = { + bitmap_clear, + bitmap_cloudy, + bitmap_fog, + bitmap_rain, + bitmap_snow, + bitmap_drizzle, + bitmap_thunderstorm, +}; + +const unsigned char temperature_icon [] PROGMEM = { + 0x1e, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x3f, 0x00, + 0x3f, 0x00, 0x1e, 0x00 +}; + +const unsigned char humidity_icon [] PROGMEM = { + 0x0c, 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x3f, 0x00, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, + 0x3f, 0x00, 0x3f, 0x00 +}; + +const unsigned char wind_icon [] PROGMEM = { + 0x00, 0x00, 0x07, 0x00, 0x07, 0x80, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0x07, 0x80, + 0x07, 0x00, 0x00, 0x00 +}; + +const unsigned char pressure_icon [] PROGMEM = { + 0x1e, 0x00, 0x3f, 0x00, 0x73, 0x80, 0xe7, 0xc0, 0xce, 0xc0, 0xdc, 0xc0, 0xe9, 0xc0, 0x73, 0x80, + 0x3f, 0x00, 0x1e, 0x00 +};