#include <Arduino.h>
#include <AsyncTCP.h>
#include <HTTPClient.h>
#include <Arduino_JSON.h>
#include <WiFi.h>
//#include <ESP8266WiFi.h>
#include "SPI.h"
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include "DHTesp.h"
#include "NTPClient.h"
#include "WiFiUdp.h"
#include "icons.h"
#include <Fonts/FreeSerif9pt7b.h>
#include "OneButton.h"
int wi=0;
const int DHT_PIN = 19;
const int buttonPin = 5;
DHTesp dhtSensor;
String openWeatherMapApiKey = "7e04cc3aaf4976b9ffd56f77d83b1fa4";
String temperature_unit = "metric";
String city = "Kyiv";
String jsonBuffer;
float OutTemperature ;
float FeelsTemperature;
int OutHumidity;
String Icon;
int Sun_rise;
int Sun_set;
String endpoint;
JSONVar readings;
JSONVar owmreadings;
String inTemp,outTemp;
String inHum,outHum;
String outFeels;
unsigned long lastTimeAcc = 0;
unsigned long OWMapDelay = 60000;
unsigned long lastTime =0;
unsigned long SensorDelay = 5000;
unsigned long OutTime=0;
unsigned long InTime =0;
unsigned long TimeTime=0;
int currentShow=0;
int firstT=0;
int firstO =0;
int run=0;
int ftrun=0;
int forun=0;
const long utcOffsetInSeconds = 7200;
char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
String months[12]={"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"};
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "pool.ntp.org", utcOffsetInSeconds);
// create ezButton object for pin 13;
unsigned long prev_count = 0;
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
#define OLED_RESET -1 // Reset pin
#define SCREEN_ADDRESS 0x3C
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
OneButton button(buttonPin, true);
unsigned long currentStateStartTime = 0;
const unsigned long stateDuration = 5000; // Тривалість кожного стану у мілісекундах
enum State {
STATE_1,
STATE_2,
STATE_3
};
State currentState = STATE_1;
// Змінні для відстеження того, чи вже було виведено значення для кожного стану
bool printedState1 = false;
bool printedState2 = false;
bool printedState3 = false;
ICACHE_RAM_ATTR void checkTicks() {
// include all buttons here to be checked
button.tick(); // just call tick() to check the state.
}
int pic =0;
int maxtime = 10000;
String httpGETRequest(const char* serverName) {
WiFiClient client;
HTTPClient http;
// Your Domain name with URL path or IP address with path
http.begin(client, serverName);
// Send HTTP POST request
int httpResponseCode = http.GET();
String payload = "{}";
if (httpResponseCode > 0) {
Serial.print("HTTP Response code: ");
Serial.println(httpResponseCode);
payload = http.getString();
}
else {
Serial.print("Error code: ");
Serial.println(httpResponseCode);
}
// Free resources
http.end();
return payload;
}
String timeConverter(long int epoch){
String sun;
int hr=(epoch % 86400L) / 3600;
int min=(epoch % 3600) / 60;
int sec=(epoch % 60);
sun= String(hr)+":"+String(min);
Serial.println(sun);
return sun;
}
void getIndoor()
{
TempAndHumidity data = dhtSensor.getTempAndHumidity();
inTemp=String(data.temperature, 0) + "C";
inHum = String(data.humidity, 0) + "%";
}
void getOutdoor()
{
endpoint = "http://api.openweathermap.org/data/2.5/weather?q=" + city + "&units=" + temperature_unit + "&appid=" + openWeatherMapApiKey;
jsonBuffer = httpGETRequest(endpoint.c_str());
JSONVar myObject = JSON.parse(jsonBuffer);
if (JSON.typeof(myObject) == "undefined") {
Serial.println("Parsing input failed!");
}
Icon = JSON.stringify(myObject["weather"][0]["icon"]);
if(Icon == "\"01d\"") wi=0;
if(Icon == "\"01n\"") wi=1;
if(Icon == "\"02d\"") wi=2;
if(Icon == "\"02n\"") wi=3;
if(Icon == "\"03d\"") wi=4;
if(Icon == "\"03n\"") wi=5;
if(Icon == "\"04d\"") wi=6;
if(Icon == "\"04n\"") wi=7;
if(Icon == "\"09d\"") wi=8;
if(Icon == "\"09n\"") wi=9;
if(Icon == "\"10d\"") wi=10;
if(Icon == "\"10n\"") wi=11;
if(Icon == "\"11d\"") wi=12;
if(Icon == "\"11n\"") wi=13;
if(Icon == "\"13d\"") wi=14;
if(Icon == "\"13n\"") wi=15;
if(Icon == "\"50d\"") wi=14;
if(Icon == "\"50n\"") wi=15;
OutTemperature = double(myObject["main"]["temp"]);
FeelsTemperature = double(myObject["main"]["feels_like"]);
OutHumidity = int(myObject["main"]["humidity"]);
Sun_rise = int(myObject["sys"]["sunrise"]);
Sun_set = int(myObject["sys"]["sunset"]);
int timeOffset = int(myObject["timezone"]);
Serial.println("Temperature: ");
Serial.println(OutTemperature);
Serial.println("OutHumidity: ");
Serial.println(OutHumidity);
outTemp = String(OutTemperature, 0) +"C";
outHum = String(OutHumidity) + "%";
outFeels = String(FeelsTemperature, 0) +"C";
}
void getOutdoor12h ()
{
endpoint = "http://api.openweathermap.org/data/2.5/forecast?q=" + city + "&units=" + temperature_unit +"&cnt=3"+ "&appid=" + openWeatherMapApiKey;
jsonBuffer = httpGETRequest(endpoint.c_str());
JSONVar myObject = JSON.parse(jsonBuffer);
if (JSON.typeof(myObject) == "undefined") {
Serial.println("Parsing input failed!");
}
}
void displayFeels()
{ display.stopscroll();
display.clearDisplay();
display.setTextSize(2);
display.setCursor(60,15);
display.print(city);
display.setCursor(15,40);
display.print(outFeels);
display.startscrollright(0x00, 0x00);
display.setCursor(0,0);
display.setTextSize(1);
display.println("Feels like");
displayWiFi();
display.display();
}
void displayIndoor()
{ display.stopscroll();
display.clearDisplay();
display.setTextSize(2);
display.setCursor(45,15);
//display.print(city);
display.setCursor(22,40);
display.print(inTemp);
display.println(" "+ inHum);
display.drawBitmap(0, 8, home , 32, 32, WHITE);
display.drawBitmap(40, 10, thermometer_celcius_small , 24, 24, WHITE);
display.drawBitmap(68, 10, humidity_small , 24, 24, WHITE);
display.startscrollright(0x00, 0x00);
display.setCursor(0,0);
display.setTextSize(1);
String header = "Indoor "+city;
display.println(header);
displayWiFi();
display.display();
}
void displayOutdoor()
{
display.stopscroll();
display.clearDisplay();
display.setTextSize(2);
display.setCursor(45,15);
// display.print(city);
display.setCursor(22,40);
display.print(outTemp);
display.println(" "+ outHum);
display.drawBitmap(0, 8, epd_bitmap_allArray[wi] , 32, 32, WHITE);
display.drawBitmap(40, 10, thermometer_celcius_small , 24, 24, WHITE);
display.drawBitmap(68, 10, humidity_small , 24, 24, WHITE);
display.startscrollright(0x00, 0x00);
display.setCursor(0,0);
display.setTextSize(1);
String header = "Outdoor "+city;
display.println(header);
displayWiFi();
display.display();
}
void displayTime(int s)
{
if (s==0)
{
timeClient.update();
unsigned long epochTime = timeClient.getEpochTime();
struct tm *ptm = gmtime ((time_t *)&epochTime);
Serial.print("Day: ");
Serial.print(daysOfTheWeek[timeClient.getDay()]);
Serial.print(", ");
Serial.print(timeClient.getHours());
Serial.print(":");
Serial.print(timeClient.getMinutes());
Serial.print(":");
Serial.println(timeClient.getSeconds());
int monthDay = ptm->tm_mday;
Serial.print("Month day: ");
Serial.println(monthDay);
int currentMonth = ptm->tm_mon+1;
Serial.print("Month: ");
Serial.println(currentMonth);
Serial.println( months[currentMonth-1]);
int currentYear = ptm->tm_year+1900;
String Date = String(monthDay)+ "/" + months[currentMonth-1] + "/"+String(currentYear);
display.stopscroll();
display.clearDisplay();
display.setTextSize(3);
display.setCursor(45,15);
//display.print(city);
display.setCursor(16,24);
if(timeClient.getMinutes()<10)
display.print(String(timeClient.getHours())+":0"+String(timeClient.getMinutes()));
else
display.print(String(timeClient.getHours())+":"+String(timeClient.getMinutes()));
display.startscrollright(0x00, 0x00);
display.setCursor(0,0);
display.setTextSize(1);
display.println(String(daysOfTheWeek[timeClient.getDay()]) +" "+ Date);
//display.println(Date);
displayWiFi();
display.display();
}
}
void displayWiFi()
{
display.drawBitmap(0, 48, epd_bitmap_wifi , 16, 16, WHITE);
//display.display();
}
void doubleClick() {
Serial.println("DoubleClick() detected.");
currentShow = 0;
display.clearDisplay();
//display.setFont(&FreeSerif9pt7b);
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(0,28);
display.println(WiFi.localIP());
getOutdoor12h ();
display.drawBitmap(60, 40, epd_bitmap_wifi , 16, 16, WHITE);
display.display();
delay(2000);
}
int curchoice=0;
unsigned long lastmillis =0;
void singleClick() {
Serial.println("SingleClick() detected.");
lastmillis = millis();
pic=1;
if(curchoice>2) curchoice = 0;
switch(curchoice)
{
case 0: city = "Kyiv";
break;
case 1: city = "Lviv";
break;
case 2: city = "London";
break;
}
display.clearDisplay();
//display.setFont(&FreeSerif9pt7b);
display.setTextSize(2);
display.setTextColor(WHITE);
display.setCursor(0,28);
display.println(city);
display.drawBitmap(60, 40, epd_bitmap_wifi , 16, 16, WHITE);
display.display();
getOutdoor();
curchoice++;
}
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
Serial.println("Hello, ESP!");
dhtSensor.setup(DHT_PIN, DHTesp::DHT22);
getIndoor();
Serial.println(inTemp);
Serial.println(inHum);
Serial.println("---");
if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
Serial.println(F("SSD1306 allocation failed"));
for(;;); // Don't proceed, loop forever
}
display.clearDisplay();
//display.setFont(&FreeSerif9pt7b);
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(0,28);
display.println("Mini Weather Station");
display.drawBitmap(60, 40, epd_bitmap_wifi , 16, 16, WHITE);
display.display();
delay(2000);
Serial.print("Connecting to WiFi");
WiFi.begin("Wokwi-GUEST", "", 6);
while (WiFi.status() != WL_CONNECTED) {
delay(100);
Serial.print(".");
}
Serial.println(" Connected!");
//WiFi.setAutoReconnect(true);
// WiFi.persistent(true);
//attachInterrupt(digitalPinToInterrupt(buttonPin), checkTicks, CHANGE);
button.attachClick(singleClick);
button.attachDoubleClick(doubleClick);
timeClient.begin();
getOutdoor();
Serial.println(Sun_rise);
Serial.println(Sun_set);
display.display();
}
void loop() {
// MUST call the loop() function first
button.tick();
delay(10);
if (millis() >= (lastmillis + maxtime))
{
pic = 0;
}
if ((millis() - lastTimeAcc) > OWMapDelay) {
// Send Events to the Web Server with the Sensor Readings
getOutdoor();
lastTimeAcc = millis();
}
if ((millis() - lastTime) > SensorDelay) {
// Send Events to the Web Server with the Sensor Readings
getIndoor();
lastTime = millis();
}
if(pic==0)
{
unsigned long currentMillis = millis();
// Визначення, чи потрібно змінити стан
if (currentMillis - currentStateStartTime >= stateDuration) {
currentStateStartTime = currentMillis; // Оновлення часу початку поточного стану
// Скидаємо прапорці виведення для нового стану
printedState1 = false;
printedState2 = false;
printedState3 = false;
// Зміна стану
switch (currentState) {
case STATE_1:
currentState = STATE_2;
break;
case STATE_2:
currentState = STATE_3;
break;
case STATE_3:
currentState = STATE_1;
break;
}
}
// Виконання дій залежно від поточного стану
switch (currentState) {
case STATE_1:
// Дії для "Стан 1"
if (!printedState1) {
Serial.println("Виконуються дії для Стану 1");
displayTime(0);
printedState1 = true;
}
break;
case STATE_2:
// Дії для "Стан 2"
if (!printedState2) {
Serial.println("Виконуються дії для Стану 2");
displayOutdoor();
printedState2 = true;
}
break;
case STATE_3:
// Дії для "Стан 3"
if (!printedState3) {
Serial.println("Виконуються дії для Стану 3");
displayIndoor();
printedState3 = true;
}
break;
}
}
}
// displayIndoor();
// delay(5000);
// displayOutdoor();
// delay(5000);