Hardware components | ||||||
| × | 1 | ||||
![]() |
| × | 1 | |||
![]() |
| × | 1 | |||
![]() |
| × | 1 | |||
Software apps and online services | ||||||
![]() |
| |||||
![]() |
| |||||
Hand tools and fabrication machines | ||||||
![]() |
| |||||
![]() |
| |||||
![]() |
| |||||
![]() |
|
This is the second version of my old project: All In One Clock 1.0 This project will have similar functions but have a touch screen and more information.
Project Goals:- Display Time (current time and date)
- Alarm clock
- Temperature right now
- Full temperature info (pressure, humidity, etc..)
- Forecast 3 days (today, tomorrow, and the day after tomorrow)
- Current weather Icon
- Timer
To be able to do all of this, we will need a connection to the internet. I chose for this project to use the Arduino RP2040 Connect. To use the RP2040, I will be using the https://create.arduino.cc/iot This official Arduino tool is very easy to use, and it's great for using the internet across multiple devices.
we have an Arduino that is connected to the internet, but how will we get the information? Well, let's divide the information we need into two categories:
- Time: To get the time, it's very simple because, while you are connected to the internet, you can get the Unix timestamp. The Unix timestamp is a way to count the time. How does it do it? It will count every second since January 1, 1970. For example, the time while writing it is "1682760531". To convert this time, I will use a library that will convert this time to a more readable time (hours, minutes, year, month, etc.).
- Temperature: To get the temperature, we will use something called an API. In short, an API is some kind of server that, when I "call it" I get JSON information back. For example, go to this link to use the NASA API that shows you the international space station location right now. http://api.open-notify.org/iss-now.json. For this project, I will use https://www.weatherapi.com. This API will have a lot of information for this project, but I will only use some of it because the Arduino cannot get so much information (we are talking about 20000 characters), so in the API settings, I changed it to only get some of the information. The API will also give me an image link, for example, cdn.weatherapi.com/weather/64x64/day/116.png. To get the image, I need to do a couple of things: get the image number, and determine if it's day or night.
All of the information mentioned above will be sent through the ISP. The Arduino will get it and decode it.
temperature = doc.containsKey("tw") ? doc["tw"] : temperature;
In this example, the Arduino will read the incoming data, and if the data has the keyword "tw" (it will be encoded as JSON) then the data will be saved in the temperature variable.
I also sent the image number and Day/Night but how will I show the image? Well, on the SD Card that is connected to the screen, there are two folders of all the images from day/night as bmp(bit map images). So I go to the SD Card and show the image by number or time.
In this project, I show icons in two ways. The first is by using a.h script, which is faster, but I can't have a lot of images like that because it takes a lot of MB. The second way is by using the SD card.
Dashboard:The Arduino IoT Cloud allows us to use a dashboard. What is a dashboard? is a way for me to see the data from anywhere and on any device.
In the dashboard, there are a lot of widgets; we will use some to show the data. We will use the button widget to have a button that will update the temperature (usually for debugging) and a couple of other widgets to show the data (temperature, humidity, pressure, and time).
Do note that if the Arduino will receive a data of a null reading(0) or will restart it can update the graph as you see(I will add in the future a way to stop that from happening).
Fonts:I used a couple of extra fonts that I will include in the download files.
The screen:I am using a 3.5-inch TFT screen; this is a touch screen. To use it, I am using the MCUFRIEND_kbv library.
We have 5 different screens; let's go through them one by one:
- Main Screen: On this screen, we can find the current time and date, the temperature, and an icon that shows the weather. Also, we have the buttons for all of the other screens.
- Forecast Screen: In this screen, we can see the forecast for the current day, tomorrow, and the day after tomorrow. For each day, there is an icon and a minimum and maximum temperature.
- Temperature Screen: In this screen, we have a lot of information that includes: temperature, humidity, pressure, UV, wind speed, Feels like
- Alarm Screen: In this screen, we can set the alarm time by using two buttons
- Timer Screen: On this screen, we have a timer display where you can set the desired time and start the countdown.
In this project we don't connect a lot of thing but we do connect some:
- Connect both Arduino's Using ISP. From the rp2040 A4-D21 and A5-D20.
- From the mega 5v to RP2040 VIN
- From the mega gnd to RP2040 GND
- From the mega 5v to vcc buzzer
- From the mega gnd to gnd buzzer
- From the mega D44 to buzzer
There is an extra 3d model for the box I used for the screen.
GitHub:You can find all of the codes and files in my GitHub
// Include necessary libraries
#include <Adafruit_GFX.h>
#include <MCUFRIEND_kbv.h>
#include <TouchScreen.h>
#include <FreeDefaultFonts.h>
#include "./fonts/FreeSans20pt7b.h"
#include "./fonts/FreeSans15pt7b.h"
#include "./fonts/FreeSans10pt7b.h"
#include "./fonts/FreeSans5pt7b.h"
#include "./fonts/digital20pt7b.h"
#include <SoftwareSerial.h>
#include "icons.h"
#include <ArduinoJson.h>
#include <Wire.h>
#include <SPI.h>
#define USE_SDFAT
#include <SdFat.h>
// Configure the SPI and SD card
SoftSpiDriver<12, 11, 13> softSpi;
SdFat SD;
#define SD_CS SdSpiConfig(10, DEDICATED_SPI, SD_SCK_MHZ(0), &softSpi)
#define PALETTEDEPTH 8 // support 256-colour Palette
// Initialize variables
int temperature;
int humidity;
int pressure;
int feelsLike;
int UV;
float windSpeed;
bool reloadTemp = false;
bool reloadForecast = false;
int hours;
int minutes;
int month;
int year;
int dayMonth;
int dayWeek = 1;
int oldMin;
int oldDayMonth;
int imageNumber = 113;
String timeOfDayForImageToday = "day";
int todayMax;
int todayMin;
int todayRain;
int todayIcon;
int tommorowMax;
int tommorowMin;
int tommorowRain;
int tommorowIcon;
int tommorow1Max;
int tommorow1Min;
int tommorow1Rain;
int tommorow1Icon;
int alarmHours = 20;
int alarmMinutes = 0;
int oldDayMM;
#define MINPRESSURE 200
#define MAXPRESSURE 1000
int Orientation = 1;
const int XP = 9, XM = A3, YP = A2, YM = 8; // 320x480 ID=0x9488
const int TS_LEFT = 120, TS_RT = 900, TS_TOP = 49, TS_BOT = 949;
MCUFRIEND_kbv tft;
TouchScreen ts = TouchScreen(XP, YP, XM, YM, 300);
Adafruit_GFX_Button temp_button, alarm_button, back_button, forecast_button, hour_up, minutes_up, dismissButton, timer_button, timerMinuteAdd_button, timerSecAdd_button, timerSecMinus_button, timerMinuteMinus_button, timerStart_button, timerClear_Button, timer5_button, timer10_button, timer15_button;
// Set up screens
enum Screen
{
MAIN,
ALARM,
TEMP,
FORECAST,
ALARM_ACTIVE,
TIMER
};
Screen currentScreen = MAIN;
// Set up colors
#define BLACK 0x0000
#define BLUE 0x001F
#define RED 0xF800
#define GREEN 0x07E0
#define CYAN 0x07FF
#define MAGENTA 0xF81F
#define YELLOW 0xFFE0
#define WHITE 0xFFFF
#define GRAY 0x8410
bool canBeOnDelay = true;
int buzzer = 44;
bool alarmScreenShown = false;
bool timerScreenShown = false;
bool reloadTempImage = false;
bool wasScreenBack = true;
unsigned long previousMillisAlarm = 0;
unsigned long previousMillisTimer = 0;
unsigned long previousMillis = 0;
const long interval = 1000;
const long intervalAlarm = 2500;
bool soundOn = false;
int pixel_x, pixel_y;
// Get touch coordinates
bool Touch_getXY(void)
{
TSPoint tp = ts.getPoint();
pinMode(YP, OUTPUT);
pinMode(XM, OUTPUT);
digitalWrite(YP, HIGH);
digitalWrite(XM, HIGH);
bool pressed = (tp.z > MINPRESSURE && tp.z < MAXPRESSURE);
if (pressed)
{
pixel_x = map(tp.y, TS_TOP, TS_BOT, 0, tft.width());
pixel_y = map(tp.x, TS_RT, TS_LEFT, 0, tft.height());
}
delay(10);
return pressed;
}
void receiveEvent(int numBytes);
// Define timer states
enum TimerState
{
TIMER_STOPPED,
TIMER_RUNNING,
TIMER_FINISHED
};
struct Timer
{
int minutes;
int seconds;
TimerState state;
unsigned long previousMillis;
const unsigned long interval = 1000;
Timer() : minutes(0), seconds(0), state(TIMER_STOPPED), previousMillis(0) {}
void update()
{
if (state == TIMER_RUNNING)
{
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval)
{
previousMillis = currentMillis;
if (seconds == 0)
{
if (minutes > 0)
{
minutes--;
seconds = 59;
}
else
{
state = TIMER_FINISHED;
}
}
else
{
seconds--;
}
if (state != TIMER_FINISHED)
{
display_new_timer();
}
}
}
}
void start()
{
if (state == TIMER_STOPPED && (minutes > 0 || seconds > 0))
{
state = TIMER_RUNNING;
previousMillis = millis();
showBMP("/timerIcon/pause.bmp", 400, 125);
}
}
void stop()
{
if (state == TIMER_RUNNING)
{
state = TIMER_STOPPED;
showBMP("/timerIcon/play.bmp", 400, 125);
}
}
void reset()
{
minutes = 0;
seconds = 0;
noTone(buzzer);
showBMP("/timerIcon/play.bmp", 400, 125);
state = TIMER_STOPPED;
}
void addMinute()
{
if (state = TIMER_RUNNING)
{
state = TIMER_STOPPED;
showBMP("/timerIcon/play.bmp", 400, 125);
}
minutes = (minutes + 1) % 100;
}
void subtractMinute()
{
if (state = TIMER_RUNNING)
{
state = TIMER_STOPPED;
showBMP("/timerIcon/play.bmp", 400, 125);
}
if (minutes > 0)
{
minutes--;
}
}
void addSecond()
{
if (state = TIMER_RUNNING)
{
state = TIMER_STOPPED;
showBMP("/timerIcon/play.bmp", 400, 125);
}
seconds = (seconds + 1) % 60;
}
void subtractSecond()
{
if (state = TIMER_RUNNING)
{
state = TIMER_STOPPED;
showBMP("/timerIcon/play.bmp", 400, 125);
}
if (seconds > 0)
{
seconds--;
}
}
void setTime(int minutesIn, int secondsIn)
{
if (state = TIMER_RUNNING)
{
state = TIMER_STOPPED;
showBMP("/timerIcon/play.bmp", 400, 125);
}
minutes = minutesIn;
seconds = secondsIn;
}
};
Timer timer;
void setup()
{
Serial.begin(9600);
// bool good = SD.begin(SD_CS);
// if (!good) {
// Serial.print(F("cannot start SD"));
// while (1);
// }
if (!SD.begin(SD_CS))
{
Serial.println("Card failed, or not present");
// Don't do anything more:
return;
}
Serial.println("SD card initialized.");
pinMode(buzzer, OUTPUT);
Wire.begin(8); // address of the Mega
Wire.onReceive(receiveEvent); // set the receive event
uint16_t ID = tft.readID();
tft.begin(ID);
tft.setRotation(Orientation);
tft.fillScreen(BLACK);
alarm_button.initButton(&tft, 52, 262, 120, 100, BLACK, BLACK, BLACK, "", 1);
timer_button.initButton(&tft, 177, 262, 120, 100, BLACK, BLACK, BLACK, "", 1);
temp_button.initButton(&tft, 302, 262, 120, 100, BLACK, BLACK, BLACK, "", 1);
forecast_button.initButton(&tft, 427, 262, 120, 100, BLACK, BLACK, BLACK, "", 1);
back_button.initButton(&tft, 430, 40, 96, 96, BLACK, BLACK, BLACK, "", 1);
timerMinuteAdd_button.initButton(&tft, 185, 40, 75, 75, BLACK, BLACK, BLACK, "", 1);
timerSecAdd_button.initButton(&tft, 305, 40, 75, 75, BLACK, BLACK, BLACK, "", 1);
timerMinuteMinus_button.initButton(&tft, 185, 190, 75, 75, BLACK, BLACK, BLACK, "", 1);
timerSecMinus_button.initButton(&tft, 305, 190, 75, 75, BLACK, BLACK, BLACK, "", 1);
timerClear_Button.initButton(&tft, 70, 110, 75, 75, BLACK, BLACK, BLACK, "", 1);
timerStart_button.initButton(&tft, 430, 155, 75, 75, BLACK, BLACK, BLACK, "", 1);
timer5_button.initButton(&tft, 150, 280, 75, 75, BLACK, BLACK, BLACK, "", 1);
timer10_button.initButton(&tft, 250, 280, 75, 75, BLACK, BLACK, BLACK, "", 1);
timer15_button.initButton(&tft, 350, 280, 75, 75, BLACK, BLACK, BLACK, "", 1);
hour_up.initButton(&tft, 150, 230, 96, 96, WHITE, WHITE, WHITE, "", 1);
minutes_up.initButton(&tft, 270, 230, 96, 96, WHITE, WHITE, WHITE, "", 1);
dismissButton.initButton(&tft, 235, 245, 211, 92, BLACK, BLACK, BLACK, "", 1);
forecast_button.drawButton(false);
temp_button.drawButton(false);
alarm_button.drawButton(false);
timer_button.drawButton(false);
defualtMain();
}
void loop()
{
timer.update();
if (timer.state == TIMER_FINISHED)
{
timerActivesScreen();
}
else
{
if ((alarmHours != hours || alarmMinutes != minutes) && !wasScreenBack)
{
wasScreenBack = true;
noTone(buzzer);
tft.fillScreen(BLACK);
defualtMain();
}
if (alarmHours == hours && alarmMinutes == minutes && canBeOnDelay && currentScreen != ALARM)
{
alarmActivesScreen();
}
else
{
switch (currentScreen)
{
case MAIN:
mainScreen();
break;
case ALARM:
alarmScreen();
break;
case TEMP:
tempScreen();
break;
case FORECAST:
forecastScreen();
break;
case TIMER:
timerScreen();
break;
}
}
}
if (alarmMinutes != minutes)
{
canBeOnDelay = true;
alarmScreenShown = false;
}
}
void mainScreen()
{
bool down = Touch_getXY();
if (down)
{
temp_button.press(temp_button.contains(pixel_x, pixel_y));
alarm_button.press(alarm_button.contains(pixel_x, pixel_y));
forecast_button.press(forecast_button.contains(pixel_x, pixel_y));
timer_button.press(timer_button.contains(pixel_x, pixel_y));
}
else
{
temp_button.press(false);
alarm_button.press(false);
forecast_button.press(false);
timer_button.press(false);
}
if (temp_button.justPressed())
{
tft.fillScreen(BLACK);
Serial.println("pressed temp");
currentScreen = TEMP;
back_button.drawButton(false);
// tft.drawRGBBitmap(390, 5, homeScreen, 80, 80);
showBMP("/home.bmp", 390, 5);
reloadTemp = false;
defaultTemp();
return;
}
if (alarm_button.justPressed())
{
Serial.println("pressed alarm");
tft.fillScreen(BLACK);
currentScreen = ALARM;
tft.setFont(&FreeSans15pt7b);
back_button.drawButton(false);
hour_up.drawButton(false);
minutes_up.drawButton(false);
defaultAlarm();
return;
}
if (forecast_button.justPressed())
{
Serial.println("pressed forecast");
tft.fillScreen(BLACK);
currentScreen = FORECAST;
back_button.drawButton(false);
reloadForecast = false;
defaultForecast();
// tft.drawRGBBitmap(390, 5, homeScreen, 80, 80);
showBMP("/home.bmp", 390, 5);
showBMP("/arrow_up_icon.bmp", 10, 160);
showBMP("/arrow_down_icon.bmp", 10, 200);
showBMP("/rainChanceIcon.bmp", 10, 240);
showBMP("/arrow_up_icon.bmp", 130, 160);
showBMP("/arrow_down_icon.bmp", 130, 200);
showBMP("/rainChanceIcon.bmp", 130, 240);
showBMP("/arrow_up_icon.bmp", 250, 160);
showBMP("/arrow_down_icon.bmp", 250, 200);
showBMP("/rainChanceIcon.bmp", 250, 240);
return;
}
if (timer_button.justPressed())
{
Serial.println("pressed timer");
tft.fillScreen(BLACK);
currentScreen = TIMER;
tft.setFont(&FreeSans15pt7b);
back_button.drawButton(false);
timerMinuteAdd_button.drawButton(false);
timerSecAdd_button.drawButton(false);
timerMinuteMinus_button.drawButton(false);
timerSecMinus_button.drawButton(false);
timerStart_button.drawButton(false);
timerClear_Button.drawButton(false);
timer5_button.drawButton(false);
timer10_button.drawButton(false);
timer15_button.drawButton(false);
showBMP("/home.bmp", 390, 5);
showBMP("/timerIcon/minus.bmp", 155, 155);
showBMP("/timerIcon/add.bmp", 155, 10);
showBMP("/timerIcon/minus.bmp", 275, 155);
showBMP("/timerIcon/add.bmp", 275, 10);
showBMP("/timerIcon/play.bmp", 400, 125);
showBMP("/timerIcon/restart.bmp", 40, 80);
showBMP("/timerIcon/number-5.bmp", 120, 250);
showBMP("/timerIcon/number-10.bmp", 220, 250);
showBMP("/timerIcon/number-15.bmp", 320, 250);
display_new_timer();
return;
}
// image+temp
if (reloadTempImage)
{
tft.fillRect(15, 0, 100, 120, BLACK);
displayImage(timeOfDayForImageToday, imageNumber, 15, 50);
tft.setFont(&FreeSans15pt7b);
tft.setTextSize(1);
tft.setCursor(20, 30);
tft.setTextColor(WHITE);
tft.print("T: ");
tft.print(String(temperature));
tft.print(" C");
reloadTempImage = false;
}
// date
if (oldDayMonth != dayMonth)
{
tft.fillRect(225, 0, 240, 50, BLACK);
tft.setCursor(230, 30);
tft.setTextSize(1);
tft.setFont(&FreeSans15pt7b);
tft.setTextColor(WHITE);
tft.print(getDayOfWeek(dayWeek) + " " + String(dayMonth / 10) + String(dayMonth % 10) + "." + String(month / 10) + String(month % 10) + "." + String(year));
oldDayMonth = dayMonth;
}
// hours:minutes
if (oldMin != minutes)
{
tft.fillRect(155, 100, 200, 90, BLACK);
tft.setCursor(160, 160);
tft.setTextColor(GREEN);
tft.setTextSize(2.9);
tft.setFont(&digital20pt7b);
tft.print(String(hours / 10) + String(hours % 10) + ":" + String(minutes / 10) + String(minutes % 10));
tft.setFont(&FreeSans15pt7b);
tft.setTextColor(WHITE);
oldMin = minutes;
}
}
void alarmScreen()
{
bool down = Touch_getXY();
back_button.press(down && back_button.contains(pixel_x, pixel_y));
hour_up.press(down && hour_up.contains(pixel_x, pixel_y));
minutes_up.press(down && minutes_up.contains(pixel_x, pixel_y));
if (back_button.justPressed())
{
Serial.println("pressed back");
if (alarmHours == hours && alarmMinutes == minutes && canBeOnDelay)
{
currentScreen = MAIN;
alarmActivesScreen();
return;
}
tft.fillScreen(BLACK);
currentScreen = MAIN;
defualtMain();
return;
}
if (hour_up.justPressed())
{
alarmHours = (alarmHours + 1) % 24;
tft.fillRect(105, 90, 200, 80, BLACK);
tft.setFont(&digital20pt7b);
tft.setTextColor(GREEN);
tft.setCursor(120, 150);
tft.setTextSize(2);
tft.print(String(alarmHours / 10) + String(alarmHours % 10) + ":" + String(alarmMinutes / 10) + String(alarmMinutes % 10));
}
if (minutes_up.justPressed())
{
canBeOnDelay = true;
alarmMinutes = (alarmMinutes + 1) % 60;
tft.fillRect(105, 90, 200, 80, BLACK);
tft.setFont(&digital20pt7b);
tft.setTextColor(GREEN);
tft.setCursor(120, 150);
tft.setTextSize(2);
tft.print(String(alarmHours / 10) + String(alarmHours % 10) + ":" + String(alarmMinutes / 10) + String(alarmMinutes % 10));
}
}
void tempScreen()
{
bool down = Touch_getXY();
back_button.press(down && back_button.contains(pixel_x, pixel_y));
if (back_button.justPressed())
{
Serial.println("pressed back");
tft.fillScreen(BLACK);
currentScreen = MAIN;
defualtMain();
return;
}
displayImage(timeOfDayForImageToday, imageNumber, 390, 250);
if (reloadTemp)
{
tft.fillRect(30, 70, 90, 40, BLACK);
tft.fillRect(160, 70, 90, 40, BLACK);
tft.fillRect(270, 70, 120, 40, BLACK);
tft.fillRect(30, 200, 90, 40, BLACK);
tft.fillRect(160, 200, 35, 40, BLACK);
tft.fillRect(230, 200, 160, 40, BLACK);
defaultTemp();
reloadTemp = false;
}
}
void forecastScreen()
{
bool down = Touch_getXY();
back_button.press(down && back_button.contains(pixel_x, pixel_y));
if (back_button.justPressed())
{
Serial.println("pressed back");
tft.fillScreen(BLACK);
defualtMain();
currentScreen = MAIN;
return;
}
if (reloadForecast)
{
tft.fillRect(45, 20, 70, 250, BLACK);
tft.fillRect(165, 20, 70, 250, BLACK);
tft.fillRect(285, 20, 70, 250, BLACK);
defaultForecast();
reloadForecast = false;
}
}
void alarmActivesScreen()
{
wasScreenBack = false;
static unsigned long lastBuzzTime = 0;
if (!alarmScreenShown)
{
tft.fillScreen(BLACK);
defaultAlarmActive();
alarmScreenShown = true;
}
unsigned long currentMillisAlarm = millis();
if (currentMillisAlarm - previousMillisAlarm >= intervalAlarm)
{
previousMillisAlarm = currentMillisAlarm;
if (soundOn)
{
soundOn = false;
noTone(buzzer);
}
else
{
soundOn = true;
analogWrite(buzzer, 200);
}
}
bool down = Touch_getXY();
dismissButton.press(down && dismissButton.contains(pixel_x, pixel_y));
if (dismissButton.justPressed())
{
Serial.println("pressed dismiss");
tft.fillScreen(BLACK);
currentScreen = MAIN;
noTone(buzzer);
defualtMain();
canBeOnDelay = false;
wasScreenBack = true;
return;
}
}
void timerScreen()
{
bool down = Touch_getXY();
back_button.press(down && back_button.contains(pixel_x, pixel_y));
timerMinuteAdd_button.press(down && timerMinuteAdd_button.contains(pixel_x, pixel_y));
timerSecAdd_button.press(down && timerSecAdd_button.contains(pixel_x, pixel_y));
timerMinuteMinus_button.press(down && timerMinuteMinus_button.contains(pixel_x, pixel_y));
timerSecMinus_button.press(down && timerSecMinus_button.contains(pixel_x, pixel_y));
timerStart_button.press(down && timerStart_button.contains(pixel_x, pixel_y));
timerClear_Button.press(down && timerClear_Button.contains(pixel_x, pixel_y));
timer5_button.press(down && timer5_button.contains(pixel_x, pixel_y));
timer10_button.press(down && timer10_button.contains(pixel_x, pixel_y));
timer15_button.press(down && timer15_button.contains(pixel_x, pixel_y));
if (back_button.justPressed())
{
tft.fillScreen(BLACK);
currentScreen = MAIN;
defualtMain();
return;
}
if (timerClear_Button.justPressed())
{
timer.reset();
display_new_timer();
}
if (timerMinuteAdd_button.justPressed())
{
timer.addMinute();
display_new_timer();
}
if (timerMinuteMinus_button.justPressed())
{
timer.subtractMinute();
display_new_timer();
}
if (timerSecAdd_button.justPressed())
{
timer.addSecond();
display_new_timer();
}
if (timerSecMinus_button.justPressed())
{
timer.subtractSecond();
display_new_timer();
}
if (timerStart_button.justPressed())
{
if (timer.state == TIMER_RUNNING)
{
timer.stop();
}
else
{
timer.start();
}
delay(500);
}
if (timer5_button.justPressed())
{
timer.setTime(5, 0);
display_new_timer();
}
if (timer10_button.justPressed())
{
timer.setTime(10, 0);
display_new_timer();
}
if (timer15_button.justPressed())
{
timer.setTime(15, 0);
display_new_timer();
}
}
void timerActivesScreen()
{
static bool timerScreenShown = false;
static unsigned long startMillis;
static const unsigned long duration = 30000; // 30 seconds
unsigned long currentMillisTimer = millis();
if (currentMillisTimer - previousMillisTimer >= intervalAlarm)
{
previousMillisTimer = currentMillisTimer;
if (soundOn)
{
soundOn = false;
noTone(buzzer);
}
else
{
soundOn = true;
analogWrite(buzzer, 200);
}
}
if (!timerScreenShown)
{
tft.fillScreen(BLACK);
defaultTimerActive();
timerScreenShown = true;
startMillis = millis();
}
unsigned long currentMillis = millis();
if (currentMillis - startMillis >= duration)
{
timerScreenShown = false;
tft.fillScreen(BLACK);
currentScreen = MAIN;
timer.reset();
defualtMain();
return;
}
bool down = Touch_getXY();
dismissButton.press(down && dismissButton.contains(pixel_x, pixel_y));
if (dismissButton.justPressed())
{
timerScreenShown = false;
tft.fillScreen(BLACK);
currentScreen = MAIN;
timer.reset();
defualtMain();
return;
}
}
void display_new_timer()
{
tft.fillRect(140, 85, 200, 65, BLACK);
tft.setFont(&digital20pt7b);
tft.setTextColor(GREEN);
tft.setCursor(155, 140);
tft.setTextSize(2);
tft.print(String(timer.minutes / 10) + String(timer.minutes % 10) + ":" + String(timer.seconds / 10) + String(timer.seconds % 10));
}
String getDayOfWeek(int dayOfWeek)
{
String dayName; // Initialize empty string for day name
if (dayOfWeek > 7)
{
dayOfWeek -= 7;
}
switch (dayOfWeek)
{
case 1:
dayName = "Sun";
break;
case 2:
dayName = "Mon";
break;
case 3:
dayName = "Tue";
break;
case 4:
dayName = "Wed";
break;
case 5:
dayName = "Thu";
break;
case 6:
dayName = "Fri";
break;
case 7:
dayName = "Sat";
break;
default:
dayName = ""; // Invalid day of week integer
break;
}
return dayName;
}
void displayImage(String timeOfDay, int imageNumber, int x, int y)
{
String filename = "/" + timeOfDay + "/" + String(imageNumber) + ".bmp";
showBMP(filename.c_str(), x, y);
}
void defaultForecast()
{
Serial.println(tommorowIcon);
tft.setTextColor(WHITE);
tft.setFont(&FreeSans15pt7b);
tft.setTextSize(1);
// today
tft.setCursor(50, 60);
tft.print(getDayOfWeek(dayWeek));
displayImage("day", todayIcon, 40, 80);
tft.setCursor(50, 180);
tft.print(String(todayMax) + "C");
tft.setCursor(50, 220);
tft.print(String(todayMin) + "C");
tft.setCursor(50, 260);
tft.print(String(todayRain) + "%");
// tommorow
tft.setCursor(170, 60);
tft.print(getDayOfWeek((dayWeek + 1)));
displayImage("day", tommorowIcon, 160, 80);
tft.setCursor(170, 180);
tft.print(String(tommorowMax) + "C");
tft.setCursor(170, 220);
tft.print(String(tommorowMin) + "C");
tft.setCursor(170, 260);
tft.print(String(tommorowRain) + "%");
// the day after tommorow
tft.setCursor(290, 60);
tft.print(getDayOfWeek((dayWeek + 2)));
displayImage("day", tommorow1Icon, 280, 80);
tft.setCursor(290, 180);
tft.print(String(tommorow1Max) + "C");
tft.setCursor(290, 220);
tft.print(String(tommorow1Min) + "C");
tft.setCursor(290, 260);
tft.print(String(tommorow1Rain) + "%");
}
void defualtMain()
{
tft.fillScreen(BLACK);
// showBMP("/timer.bmp", 145, 230);
// tft.drawRGBBitmap(20, 230, alarmIcon, 64, 64);
showBMP("/clock.bmp", 20, 230);
showBMP("/timer.bmp", 145, 230);
showBMP("/temperature.bmp", 270, 230);
// tft.drawRGBBitmap(270, 230, tempIcon, 64, 64);
showBMP("/forecast.bmp", 395, 230);
// tft.drawRGBBitmap(395, 230, forecastIcon, 64, 64);
displayImage(timeOfDayForImageToday, imageNumber, 15, 50);
tft.fillRect(15, 0, 150, 50, BLACK);
tft.setFont(&FreeSans15pt7b);
tft.setTextSize(1);
tft.setCursor(20, 30);
tft.setTextColor(WHITE);
tft.print("T: ");
tft.print(String(temperature));
tft.print(" C");
tft.fillRect(225, 0, 240, 50, BLACK);
tft.setCursor(230, 30);
tft.setTextSize(1);
tft.setFont(&FreeSans15pt7b);
tft.setTextColor(WHITE);
tft.print(getDayOfWeek(dayWeek) + " " + String(dayMonth / 10) + String(dayMonth % 10) + "." + String(month / 10) + String(month % 10) + "." + String(year));
tft.fillRect(155, 100, 200, 90, BLACK);
tft.setCursor(160, 160);
tft.setTextColor(GREEN);
tft.setTextSize(2.9);
tft.setFont(&digital20pt7b);
tft.print(String(hours / 10) + String(hours % 10) + ":" + String(minutes / 10) + String(minutes % 10));
tft.setTextColor(WHITE);
tft.setTextSize(1);
}
void defaultTemp()
{
tft.setTextSize(1);
// Temperature
tft.setCursor(20, 60);
tft.setTextColor(GRAY);
tft.setFont(&FreeSans10pt7b);
tft.print("Temperature");
tft.setTextColor(WHITE);
tft.setFont(&FreeSans20pt7b);
tft.setCursor(40, 105);
tft.print(String(temperature) + "C");
// humidity
tft.setCursor(160, 60);
tft.setTextColor(GRAY);
tft.setFont(&FreeSans10pt7b);
tft.print("Humidity");
tft.setTextColor(WHITE);
tft.setFont(&FreeSans20pt7b);
tft.setCursor(160, 105);
tft.print(String(humidity) + "%");
// Pressure
tft.setCursor(270, 60);
tft.setTextColor(GRAY);
tft.setFont(&FreeSans10pt7b);
tft.print("Pressure");
tft.setTextColor(WHITE);
tft.setFont(&FreeSans20pt7b);
tft.setCursor(270, 105);
tft.print(pressure);
// Feels Like
tft.setCursor(20, 190);
tft.setTextColor(GRAY);
tft.setFont(&FreeSans10pt7b);
tft.print("Feels Like");
tft.setTextColor(WHITE);
tft.setFont(&FreeSans20pt7b);
tft.setCursor(35, 230);
tft.print(String(feelsLike) + "C");
// UV
tft.setCursor(160, 190);
tft.setTextColor(GRAY);
tft.setFont(&FreeSans10pt7b);
tft.print("UV");
tft.setTextColor(WHITE);
tft.setFont(&FreeSans20pt7b);
tft.setCursor(165, 230);
tft.print(UV);
// wind Speed
tft.setCursor(255, 190);
tft.setTextColor(GRAY);
tft.setFont(&FreeSans10pt7b);
tft.print("wind Speed");
tft.setTextColor(WHITE);
tft.setFont(&FreeSans20pt7b);
tft.setCursor(230, 230);
tft.print(String(windSpeed, 1) + "KPH");
}
void defaultAlarm()
{
tft.fillRect(102, 182, 96, 96, WHITE);
tft.fillRect(105, 185, 90, 90, BLACK);
tft.setCursor(120, 255);
tft.setFont(&FreeSans20pt7b);
tft.setTextSize(2);
tft.print("H");
tft.fillRect(222, 182, 96, 96, WHITE);
tft.fillRect(225, 185, 90, 90, BLACK);
tft.setCursor(240, 255);
tft.setFont(&FreeSans20pt7b);
tft.setTextSize(2);
tft.print("M");
// tft.drawRGBBitmap(390, 5, homeScreen, 80, 80);
showBMP("/home.bmp", 390, 5);
tft.setTextColor(WHITE);
tft.setFont(&FreeSans15pt7b);
tft.setTextSize(1);
tft.setCursor(150, 40);
tft.print("Set Alarm");
tft.setFont(&digital20pt7b);
tft.setTextColor(GREEN);
tft.setCursor(120, 150);
tft.setTextSize(2);
tft.print(String(alarmHours / 10) + String(alarmHours % 10) + ":" + String(alarmMinutes / 10) + String(alarmMinutes % 10));
}
void defaultAlarmActive()
{
dismissButton.drawButton(false);
tft.setTextSize(1);
tft.setTextColor(WHITE);
tft.setFont(&FreeSans20pt7b);
// tft.drawRGBBitmap(180, 20, alarmIcon, 64, 64);
showBMP("/clock.bmp", 180, 20);
tft.setCursor(150, 140);
tft.print("ALARM");
tft.setCursor(150, 200);
tft.print(String(alarmHours / 10) + String(alarmHours % 10) + ":" + String(alarmMinutes / 10) + String(alarmMinutes % 10));
tft.fillRect(150, 220, 174, 48, WHITE);
...
This file has been truncated, please download it to see its full contents.
/*
Arduino IoT Cloud Variables description
The following variables are automatically generated and updated when changes are made to the Thing
String time_str;
int dayMonth;
int dayWeek;
int hours;
int humidity;
int minutes;+++
int monthNow;
int pressure;
int temp;
int yearNow;
bool override_send;
Variables which are marked as READ/WRITE in the Cloud Thing will also have functions
which are called when their values are changed from the Dashboard.
These functions are generated with the Thing and added at the end of this sketch.
*/
#include "thingProperties.h"
#include <Wire.h>
#include <WiFi.h>
#include <ArduinoJson.h>
#include <ArduinoHttpClient.h>
#include "TimeLib.h"
#include <WiFiClient.h>
// Set up WiFi network credentials
const char* ssid = "ssid";
const char* password = "password";
const char* host = "api.weatherapi.com";
const int port = 80;
// Your API key
const char* apiKey = "key";
WiFiClient wifiClient;
HttpClient client = HttpClient(wifiClient, host, port);
unsigned long previousMillis = 0;
// constants won't change:
const long interval = 300000; //5 min
// const long interval = 5000; //5 sec
unsigned long previousMillis1 = 0;
// constants won't change:
const long interval1 = 30000; //30 sec
int minuteOld = 0;
void setup() {
// Initialize serial and wait for port to open:
Serial.begin(9600);
Wire.begin();
delay(1000);
WiFi.begin(ssid, password);
int failedAttempts = 0;
while (WiFi.status() != WL_CONNECTED) {
if (failedAttempts >= 5) {
Serial.println("Failed to connect to WiFi. Resetting...");
delay(2000);
NVIC_SystemReset(); // Reset the Arduino RP2040
}
delay(1000);
Serial.println("Connecting to WiFi...");
failedAttempts++;
}
Serial.println("Connected to WiFi");
//timeZoneOffset = ArduinoCloud.getTimeZoneOffset();
// This delay gives the chance to wait for a Serial Monitor without blocking if none is found
delay(1500);
// Defined in thingProperties.h
initProperties();
// Connect to Arduino IoT Cloud
ArduinoCloud.begin(ArduinoIoTPreferredConnection);
/*
The following function allows you to obtain more information
related to the state of network and IoT Cloud connection and errors
the higher number the more granular information you’ll get.
The default is 0 (only errors).
Maximum is 4
*/
setDebugMessageLevel(2);
ArduinoCloud.printDebugInfo();
}
void loop() {
ArduinoCloud.update();
//5 min delay
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval || override_send) {
previousMillis = currentMillis;
if (client.connect(host, port)) {
Serial.println("Connected to server");
String url = "/v1/forecast.json?key=";
url += apiKey;
url += "&q=modiin,IL&days=3";
client.print(String("GET ") + url + " HTTP/1.1\r\n" +
"Host: " + host + "\r\n" +
"Connection: close\r\n\r\n"); // remove the headers section
while (!client.available()) {
delay(10);
}
String response = client.readString();
Serial.println("----");
Serial.println(response);
int firstOpeiningBracket = response.indexOf('{');
String data = response.substring(firstOpeiningBracket);
StaticJsonDocument<5000> doc;
DeserializationError error = deserializeJson(doc, data);
if (error) {
Serial.print("deserializeJson() failed: ");
Serial.println(error.f_str());
return;
}
temp = doc["current"]["temp_c"];
humidity = doc["current"]["humidity"];
pressure = doc["current"]["pressure_mb"];
String todayIconUrl = doc["current"]["condition"]["icon"];
StaticJsonDocument<200> jsonOpenWeatherMapTHP;
jsonOpenWeatherMapTHP["tw"] = temp;
jsonOpenWeatherMapTHP["hw"] = humidity;
jsonOpenWeatherMapTHP["pw"] = pressure;
String jsonStringOpenWeatherMapTHP;
serializeJson(jsonOpenWeatherMapTHP, jsonStringOpenWeatherMapTHP);
Wire.beginTransmission(8);
if(jsonStringOpenWeatherMapTHP.length() < 34){
Wire.write(jsonStringOpenWeatherMapTHP.c_str(), jsonStringOpenWeatherMapTHP.length());
}else{
Serial.println("Too long max of 32 bytes");
}
Wire.endTransmission();
StaticJsonDocument<200> jsonOpenWeatherMapTodayIcon;
int start = todayIconUrl.lastIndexOf("/") + 1;
int end = todayIconUrl.lastIndexOf(".");
String numStr = todayIconUrl.substring(start, end);
int num = numStr.toInt();
String timeOfDayForImageToday = "day";
if (todayIconUrl.indexOf("day") != -1) {
timeOfDayForImageToday = "day";
} else if (todayIconUrl.indexOf("night") != -1) {
timeOfDayForImageToday = "night";
}
jsonOpenWeatherMapTodayIcon["int"] = num;
jsonOpenWeatherMapTodayIcon["nort"] = timeOfDayForImageToday;
String jsonStringOpenWeatherMapTodayIcon;
serializeJson(jsonOpenWeatherMapTodayIcon, jsonStringOpenWeatherMapTodayIcon);
Wire.beginTransmission(8);
if(jsonStringOpenWeatherMapTodayIcon.length() < 34){
Wire.write(jsonStringOpenWeatherMapTodayIcon.c_str(), jsonStringOpenWeatherMapTodayIcon.length());
}else{
Serial.println("Too long max of 32 bytes");
}
Wire.endTransmission();
StaticJsonDocument<200> jsonOpenWeatherMapTodayFullInfo;
int feels_like = doc["current"]["feelslike_c"];
int uv = doc["current"]["uv"];
float wind_speed = doc["current"]["wind_kph"];
jsonOpenWeatherMapTodayFullInfo["flt"] = feels_like;
jsonOpenWeatherMapTodayFullInfo["uv"] = uv;
jsonOpenWeatherMapTodayFullInfo["wst"] = String(wind_speed,1);
String jsonStringOpenWeatherMapFullInfo;
serializeJson(jsonOpenWeatherMapTodayFullInfo, jsonStringOpenWeatherMapFullInfo);
Wire.beginTransmission(8);
if(jsonStringOpenWeatherMapFullInfo.length() < 34){
Wire.write(jsonStringOpenWeatherMapFullInfo.c_str(), jsonStringOpenWeatherMapFullInfo.length());
}else{
Serial.println("Too long max of 32 bytes");
}
Wire.endTransmission();
StaticJsonDocument<200> jsonOpenWeatherMapTodayForecast;
int todayMaxTemp = doc["forecast"]["forecastday"][0]["day"]["maxtemp_c"];
int todayMinTemp = doc["forecast"]["forecastday"][0]["day"]["mintemp_c"];
int todayRain = doc["forecast"]["forecastday"][0]["day"]["daily_chance_of_rain"];
String todayIcon = doc["forecast"]["forecastday"][0]["day"]["condition"]["icon"];
start = todayIcon.lastIndexOf("/") + 1;
end = todayIcon.lastIndexOf(".");
numStr = todayIcon.substring(start, end);
int iconNumberTodayForecast = numStr.toInt();
jsonOpenWeatherMapTodayForecast["t1mx"] = todayMaxTemp;
jsonOpenWeatherMapTodayForecast["t1mi"] = todayMinTemp;
jsonOpenWeatherMapTodayForecast["t1r"] = todayRain;
String jsonStringOpenWeatherMapTodayForecast;
serializeJson(jsonOpenWeatherMapTodayForecast, jsonStringOpenWeatherMapTodayForecast);
Wire.beginTransmission(8);
if(jsonStringOpenWeatherMapTodayForecast.length() < 34){
Wire.write(jsonStringOpenWeatherMapTodayForecast.c_str(), jsonStringOpenWeatherMapTodayForecast.length());
}else{
Serial.println("Too long max of 32 bytes");
}
Wire.endTransmission();
StaticJsonDocument<200> jsonOpenWeatherMapTommorowForecast;
int tommorowMaxTemp = doc["forecast"]["forecastday"][1]["day"]["maxtemp_c"];
int tommorowMinTemp = doc["forecast"]["forecastday"][1]["day"]["mintemp_c"];
int tommorowRain = doc["forecast"]["forecastday"][1]["day"]["daily_chance_of_rain"];
String tommorowIcon = doc["forecast"]["forecastday"][1]["day"]["condition"]["icon"];
start = tommorowIcon.lastIndexOf("/") + 1;
end = tommorowIcon.lastIndexOf(".");
numStr = tommorowIcon.substring(start, end);
int iconNumberTommorowForecast = numStr.toInt();
jsonOpenWeatherMapTommorowForecast["t2mx"] = tommorowMaxTemp;
jsonOpenWeatherMapTommorowForecast["t2mi"] = tommorowMinTemp;
jsonOpenWeatherMapTommorowForecast["t2r"] = tommorowRain;
String jsonStringOpenWeatherMapTommorowForecast;
serializeJson(jsonOpenWeatherMapTommorowForecast, jsonStringOpenWeatherMapTommorowForecast);
Wire.beginTransmission(8);
if(jsonStringOpenWeatherMapTommorowForecast.length() < 34){
Wire.write(jsonStringOpenWeatherMapTommorowForecast.c_str(), jsonStringOpenWeatherMapTommorowForecast.length());
}else{
Serial.println("Too long max of 32 bytes");
}
Wire.endTransmission();
StaticJsonDocument<200> jsonOpenWeatherMapTommorow1Forecast;
int tommorow1MaxTemp = doc["forecast"]["forecastday"][2]["day"]["maxtemp_c"];
int tommorow1MinTemp = doc["forecast"]["forecastday"][2]["day"]["mintemp_c"];
int tommorow1Rain = doc["forecast"]["forecastday"][2]["day"]["daily_chance_of_rain"];
String tommorow1Icon = doc["forecast"]["forecastday"][2]["day"]["condition"]["icon"];
start = tommorow1Icon.lastIndexOf("/") + 1;
end = tommorow1Icon.lastIndexOf(".");
numStr = tommorow1Icon.substring(start, end);
int iconNumberTommorow1Forecast = numStr.toInt();
jsonOpenWeatherMapTommorow1Forecast["t3mx"] = tommorow1MaxTemp;
jsonOpenWeatherMapTommorow1Forecast["t3mi"] = tommorow1MinTemp;
jsonOpenWeatherMapTommorow1Forecast["t3r"] = tommorow1Rain;
String jsonStringOpenWeatherMapTommorow1Forecast;
serializeJson(jsonOpenWeatherMapTommorow1Forecast, jsonStringOpenWeatherMapTommorow1Forecast);
Wire.beginTransmission(8);
if(jsonStringOpenWeatherMapTommorow1Forecast.length() < 34){
Wire.write(jsonStringOpenWeatherMapTommorow1Forecast.c_str(), jsonStringOpenWeatherMapTommorow1Forecast.length());
}else{
Serial.println("Too long max of 32 bytes");
}
Wire.endTransmission();
StaticJsonDocument<200> jsonOpenWeatherMapForecastIcons;
jsonOpenWeatherMapForecastIcons["t1c"] = iconNumberTodayForecast;
jsonOpenWeatherMapForecastIcons["t2c"] = iconNumberTommorowForecast;
jsonOpenWeatherMapForecastIcons["t3c"] = iconNumberTommorow1Forecast;
String jsonStringOpenWeatherMapForecastIcons;
serializeJson(jsonOpenWeatherMapForecastIcons, jsonStringOpenWeatherMapForecastIcons);
Wire.beginTransmission(8);
if(jsonStringOpenWeatherMapForecastIcons.length() < 34){
Wire.write(jsonStringOpenWeatherMapForecastIcons.c_str(), jsonStringOpenWeatherMapForecastIcons.length());
}else{
Serial.println("Too long max of 32 bytes");
}
Wire.endTransmission();
Serial.print("Temperature: ");
Serial.println(temp);
Serial.print("Humidity: ");
Serial.println(humidity);
Serial.print("Pressure: ");
Serial.println(pressure);
Serial.println(todayMaxTemp);
Serial.print("Today's Min Temperature: ");
Serial.println(todayMinTemp);
Serial.print("Today's Icon URL: ");
Serial.println(todayIconUrl);
client.stop();
} else {
Serial.println("Connection failed");
}
}
time_t utcCalc = ArduinoCloud.getLocalTime();
minutes = minute(utcCalc);
if (minutes != minuteOld) {
previousMillis1 = currentMillis;
time_t utcCalc = ArduinoCloud.getLocalTime();
hours = hour(utcCalc);
minutes = minute(utcCalc);
monthNow = month(utcCalc);
yearNow = year(utcCalc);
dayMonth = day(utcCalc);
dayWeek = weekday(utcCalc);
StaticJsonDocument<200> jsonTimeHMM;
jsonTimeHMM["ht"] = hours;
jsonTimeHMM["mit"] = minutes;
jsonTimeHMM["mot"] = monthNow;
StaticJsonDocument<200> jsonTimeYDD;
jsonTimeYDD["yt"] = yearNow;
jsonTimeYDD["dmt"] = dayMonth;
jsonTimeYDD["dwt"] = dayWeek;
time_str = String(hours/10)+String(hours%10)+":"+String(minutes/10)+String(minutes%10);
String jsonStringTimeHMM;
serializeJson(jsonTimeHMM, jsonStringTimeHMM);
String jsonStringTimeYDD;
serializeJson(jsonTimeYDD, jsonStringTimeYDD);
Wire.beginTransmission(8);
if(jsonStringTimeHMM.length() < 34){
Wire.write(jsonStringTimeHMM.c_str(), jsonStringTimeHMM.length());
}else{
Serial.println("Too long max of 32 bytes");
}
Wire.endTransmission();
Wire.beginTransmission(8);
if(jsonStringTimeYDD.length() < 34){
Wire.write(jsonStringTimeYDD.c_str(), jsonStringTimeYDD.length());
}else{
Serial.println("Too long max of 32 bytes");
}
Wire.endTransmission();
Serial.print(hours);
Serial.print(":");
Serial.println(minutes);
Serial.print(dayMonth);
Serial.print(".");
Serial.print(monthNow);
Serial.print(".");
Serial.print(yearNow);
Serial.print(".");
Serial.println(dayWeek);
}
minuteOld = minutes;
}
/*
Since DayWeek is READ_WRITE variable, onDayWeekChange() is
executed every time a new value is received from IoT Cloud.
*/
void onDayWeekChange() {
// Add your code here to act upon DayWeek change
}
/*
Since Minutes is READ_WRITE variable, onMinutesChange() is
executed every time a new value is received from IoT Cloud.
*/
void onMinutesChange() {
// Add your code here to act upon Minutes change
}
/*
Since OverrideSend is READ_WRITE variable, onOverrideSendChange() is
executed every time a new value is received from IoT Cloud.
*/
void onOverrideSendChange() {
// Add your code here to act upon OverrideSend change
}
Comments
Please log in or sign up to comment.