This commit is contained in:
Tomislav Kopić 2024-02-07 20:06:07 +01:00
commit 0b48b6044e
9 changed files with 278 additions and 0 deletions

BIN
Bitmaps/Clear.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 393 B

BIN
Bitmaps/Drizzle.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 382 B

BIN
Bitmaps/Fog.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 481 B

BIN
Bitmaps/Hail.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 482 B

BIN
Bitmaps/Rain.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 436 B

BIN
Bitmaps/Snow.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 406 B

BIN
Bitmaps/Thunderstorms.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 370 B

207
D1_mini_weather_station.ino Normal file
View File

@ -0,0 +1,207 @@
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <ArduinoJson.h>
#include <Wire.h>
#include <NTPClient.h>
#include <WiFiUdp.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#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<char*>(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);
}

71
bitmaps.h Normal file
View File

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