284 lines
10 KiB
C++
284 lines
10 KiB
C++
///////////////////////////////////////////////////////////////////////////////
|
|
// Tyler Perkins
|
|
// 19-9-21
|
|
// weather panel
|
|
//
|
|
|
|
#include "weather.hpp"
|
|
#include "weather_config.hpp"
|
|
|
|
using namespace dashboard::panel;
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// Constructors ///////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
weather::weather(){
|
|
std::cerr << "WEATHER CONSTRUCTOR\n";
|
|
_time_on_screen = WEATHER_DEFAULT_ON_SCREEN_TIME;
|
|
_update_interval = std::chrono::milliseconds{WEATHER_UPDATE_INTERVAL};
|
|
_texture = nullptr;
|
|
_title = WEATHER_TITLE;
|
|
api_curl = nullptr;
|
|
|
|
weather_string["clearday"] = WEATHER_CLEAR_DAY;
|
|
weather_string["clearnight"] = WEATHER_CLEAR_NIGHT;
|
|
weather_string["pcloudyday"] = WEATHER_PCLOUDY_DAY;
|
|
weather_string["pcloudynight"] = WEATHER_PCLOUDY_NIGHT;
|
|
weather_string["mcloudyday"] = WEATHER_MCLOUDY_DAY;
|
|
weather_string["mcloudynight"] = WEATHER_MCLOUDY_NIGHT;
|
|
weather_string["cloudyday"] = WEATHER_CLOUDY_DAY;
|
|
weather_string["cloudynight"] = WEATHER_CLOUDY_NIGHT;
|
|
weather_string["humidday"] = WEATHER_HUMID_DAY;
|
|
weather_string["humidnight"] = WEATHER_HUMID_NIGHT;
|
|
weather_string["lightrainday"] = WEATHER_LRAIN_DAY;
|
|
weather_string["lightrainnight"] = WEATHER_LRAIN_NIGHT;
|
|
weather_string["rainday"] = WEATHER_RAIN_DAY;
|
|
weather_string["rainnight"] = WEATHER_RAIN_NIGHT;
|
|
weather_string["oshowerday"] = WEATHER_OSHOWER_DAY;
|
|
weather_string["oshowernight"] = WEATHER_OSHOWER_NIGHT;
|
|
weather_string["ishowerday"] = WEATHER_ISHOWER_DAY;
|
|
weather_string["ishowernight"] = WEATHER_ISHOWER_NIGHT;
|
|
weather_string["lightsnowday"] = WEATHER_LSNOW_DAY;
|
|
weather_string["lightsnownight"] = WEATHER_LSNOW_NIGHT;
|
|
weather_string["snowday"] = WEATHER_SNOW_DAY;
|
|
weather_string["snownight"] = WEATHER_SNOW_NIGHT;
|
|
weather_string["rainsnowday"] = WEATHER_RAINSNOW_DAY;
|
|
weather_string["rainsnownight"] = WEATHER_RAINSNOW_NIGHT;
|
|
}
|
|
|
|
weather::~weather(){
|
|
std::cerr << "WEATHER DECONSTRUCTOR\n";
|
|
if(_texture != nullptr){
|
|
SDL_DestroyTexture(_texture);
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// Draw function //////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
void weather::draw(){
|
|
//create the texture if this is the first time running draw
|
|
if(_texture == nullptr){
|
|
initTexture();
|
|
update();
|
|
update_texture();
|
|
}
|
|
|
|
//check if its time to update
|
|
if((std::chrono::high_resolution_clock::now() - _last_update)
|
|
> _update_interval){
|
|
update();
|
|
|
|
update_texture();
|
|
}
|
|
|
|
SDL_RenderCopy(board::getRenderer(), _texture, NULL, NULL);
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// Helper functions ///////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
///////////////////////////////////////
|
|
// Update the information of the obj
|
|
// This DOES NOT update the display
|
|
void weather::update() {
|
|
std::cerr << "WEATHER::UPDATE\n";
|
|
_last_update = std::chrono::high_resolution_clock::now();
|
|
|
|
//fetch updates
|
|
//do curl setup and cleanup
|
|
//We cleanup after each operation to save on memory.
|
|
//This is because by default we only fetch every hour
|
|
if(api_curl == nullptr){
|
|
std::cerr << "GRABING WEATHER DATA\n";
|
|
api_curl = curl_easy_init();
|
|
curl_easy_setopt(api_curl, CURLOPT_URL, WEATHER_URL_SOURCE);
|
|
curl_easy_setopt(api_curl, CURLOPT_WRITEFUNCTION,
|
|
dashboard::panel::weather::curl_callback);
|
|
curl_easy_setopt(api_curl, CURLOPT_WRITEDATA, &json_string);
|
|
CURLcode res = curl_easy_perform(api_curl);
|
|
curl_easy_cleanup(api_curl);
|
|
api_curl = nullptr;
|
|
}
|
|
|
|
//prase the response
|
|
json_doc.Parse(json_string.c_str());
|
|
|
|
//update internal state
|
|
const rapidjson::Value& curr_entry = json_doc["dataseries"];
|
|
//get all entries
|
|
weather_today = &weather_string.at(curr_entry[0]["weather"].GetString());
|
|
weather_tommorow = &weather_string.at(curr_entry[7]["weather"].GetString());
|
|
weather_day_after = &weather_string.at(curr_entry[15]["weather"].GetString());
|
|
temp_today = curr_entry[0]["temp2m"].GetInt();
|
|
temp_tommorow = curr_entry[7]["temp2m"].GetInt();
|
|
temp_day_after = curr_entry[15]["temp2m"].GetInt();
|
|
|
|
|
|
if(!WEATHER_METRIC){
|
|
temp_today = (temp_today * 1.8) + 32;
|
|
temp_tommorow = (temp_tommorow * 1.8) + 32;
|
|
temp_day_after = (temp_day_after * 1.8) + 32;
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////
|
|
// Update the texture that is being
|
|
// displayed, based on data in the json feed
|
|
void weather::update_texture(){
|
|
std::cerr << "WEATHER::UPDATE_TEXTURE\n";
|
|
SDL_Rect tgt;
|
|
std::string temp;
|
|
|
|
SDL_SetRenderTarget(board::getRenderer(), _texture);
|
|
SDL_RenderClear(board::getRenderer());
|
|
|
|
//background image
|
|
SDL_RenderCopy(board::getRenderer(),
|
|
board::getImage("weather_background.png"), NULL, NULL);
|
|
|
|
//current weather
|
|
tgt.y = 50;
|
|
TTF_SizeText(board::getFont({ "Roboto_Mono/RobotoMono-Medium.ttf", 50 }),
|
|
"Currently,",
|
|
&tgt.w, &tgt.h);
|
|
tgt.x = (SCREEN_WIDTH / 2) - (tgt.w / 2);
|
|
SDL_RenderCopy(board::getRenderer(),
|
|
board::getString("Currently,",
|
|
{ "Roboto_Mono/RobotoMono-Medium.ttf", 50 }), NULL, &tgt);
|
|
tgt.y += tgt.h;
|
|
TTF_SizeText(board::getFont({ "Roboto_Mono/RobotoMono-Medium.ttf", 50 }),
|
|
weather_today->first.c_str(),
|
|
&tgt.w, &tgt.h);
|
|
tgt.x = (SCREEN_WIDTH / 2) - (tgt.w / 2);
|
|
SDL_RenderCopy(board::getRenderer(),
|
|
board::getString(weather_today->first.c_str(),
|
|
{ "Roboto_Mono/RobotoMono-Medium.ttf", 50 }), NULL, &tgt);
|
|
tgt.y += tgt.h;
|
|
temp = std::to_string(temp_today);
|
|
if(WEATHER_METRIC)
|
|
temp += "*C";
|
|
else
|
|
temp += "*F";
|
|
TTF_SizeText(board::getFont({ "Roboto_Mono/RobotoMono-Medium.ttf", 50 }),
|
|
temp.c_str(),
|
|
&tgt.w, &tgt.h);
|
|
tgt.x = (SCREEN_WIDTH / 2) - (tgt.w / 2);
|
|
SDL_RenderCopy(board::getRenderer(),
|
|
board::getString(temp.c_str(),
|
|
{ "Roboto_Mono/RobotoMono-Medium.ttf", 50 }), NULL, &tgt);
|
|
|
|
|
|
|
|
//tommorow's weather
|
|
TTF_SizeText(board::getFont({ "Roboto_Mono/RobotoMono-Medium.ttf", 50 }),
|
|
"Tommorow,",
|
|
&tgt.w, &tgt.h);
|
|
tgt.y = (3*SCREEN_HEIGHT / 4) - (tgt.h / 2);
|
|
tgt.x = (SCREEN_WIDTH / 6) - (tgt.w / 2);
|
|
SDL_RenderCopy(board::getRenderer(),
|
|
board::getString("Tommorow,",
|
|
{ "Roboto_Mono/RobotoMono-Medium.ttf", 50 }), NULL, &tgt);
|
|
tgt.y += tgt.h;
|
|
TTF_SizeText(board::getFont({ "Roboto_Mono/RobotoMono-Medium.ttf", 50 }),
|
|
weather_tommorow->first.c_str(),
|
|
&tgt.w, &tgt.h);
|
|
tgt.x = (SCREEN_WIDTH / 6) - (tgt.w / 2);
|
|
SDL_RenderCopy(board::getRenderer(),
|
|
board::getString(weather_tommorow->first.c_str(),
|
|
{ "Roboto_Mono/RobotoMono-Medium.ttf", 50 }), NULL, &tgt);
|
|
tgt.y += tgt.h;
|
|
temp = std::to_string(temp_tommorow);
|
|
if(WEATHER_METRIC)
|
|
temp += "*C";
|
|
else
|
|
temp += "*F";
|
|
TTF_SizeText(board::getFont({ "Roboto_Mono/RobotoMono-Medium.ttf", 50 }),
|
|
temp.c_str(),
|
|
&tgt.w, &tgt.h);
|
|
tgt.x = (SCREEN_WIDTH / 6) - (tgt.w / 2);
|
|
SDL_RenderCopy(board::getRenderer(),
|
|
board::getString(temp.c_str(),
|
|
{ "Roboto_Mono/RobotoMono-Medium.ttf", 50 }), NULL, &tgt);
|
|
//icon
|
|
tgt.w = (SCREEN_WIDTH / 3) - 50;
|
|
tgt.h = tgt.w;
|
|
tgt.y = DEF_OVERLAY_BAR_HEIGHT + 25;
|
|
tgt.x = 0;
|
|
|
|
SDL_RenderCopy(board::getRenderer(),
|
|
board::getImage(weather_tommorow->second),
|
|
NULL, &tgt);
|
|
|
|
|
|
//day after's weather
|
|
TTF_SizeText(board::getFont({ "Roboto_Mono/RobotoMono-Medium.ttf", 50 }),
|
|
"Day after,",
|
|
&tgt.w, &tgt.h);
|
|
tgt.y = (3*SCREEN_HEIGHT / 4) - (tgt.h / 2);
|
|
tgt.x = (5*SCREEN_WIDTH / 6) - (tgt.w / 2);
|
|
SDL_RenderCopy(board::getRenderer(),
|
|
board::getString("Day after,",
|
|
{ "Roboto_Mono/RobotoMono-Medium.ttf", 50 }), NULL, &tgt);
|
|
tgt.y += tgt.h;
|
|
TTF_SizeText(board::getFont({ "Roboto_Mono/RobotoMono-Medium.ttf", 50 }),
|
|
weather_day_after->first.c_str(),
|
|
&tgt.w, &tgt.h);
|
|
tgt.x = (5*SCREEN_WIDTH / 6) - (tgt.w / 2);
|
|
SDL_RenderCopy(board::getRenderer(),
|
|
board::getString(weather_day_after->first.c_str(),
|
|
{ "Roboto_Mono/RobotoMono-Medium.ttf", 50 }), NULL, &tgt);
|
|
tgt.y += tgt.h;
|
|
temp = std::to_string(temp_day_after);
|
|
if(WEATHER_METRIC)
|
|
temp += "*C";
|
|
else
|
|
temp += "*F";
|
|
TTF_SizeText(board::getFont({ "Roboto_Mono/RobotoMono-Medium.ttf", 50 }),
|
|
temp.c_str(),
|
|
&tgt.w, &tgt.h);
|
|
tgt.x = (5*SCREEN_WIDTH / 6) - (tgt.w / 2);
|
|
SDL_RenderCopy(board::getRenderer(),
|
|
board::getString(temp.c_str(),
|
|
{ "Roboto_Mono/RobotoMono-Medium.ttf", 50 }), NULL, &tgt);
|
|
//icon
|
|
tgt.w = (SCREEN_WIDTH / 3) - 50;
|
|
tgt.h = tgt.w;
|
|
tgt.y = DEF_OVERLAY_BAR_HEIGHT + 25;
|
|
tgt.x = (2*SCREEN_WIDTH / 3);
|
|
std::cerr << "WEATHER DAY AFTER " << weather_day_after->second << "\n";
|
|
std::cerr << board::getImage(weather_day_after->second) << "\n";
|
|
|
|
SDL_RenderCopy(board::getRenderer(),
|
|
board::getImage(weather_day_after->second),
|
|
NULL, &tgt);
|
|
|
|
SDL_SetRenderTarget(board::getRenderer(), NULL);
|
|
}
|
|
|
|
///////////////////////////////////////
|
|
// Lazy load the texture object
|
|
// This is to make sure that all of SDL
|
|
// is init before we attempt to draw anything
|
|
void weather::initTexture(){
|
|
if(_texture == nullptr){
|
|
_texture = SDL_CreateTexture(board::getRenderer(),
|
|
SDL_PIXELFORMAT_RGBA8888,
|
|
SDL_TEXTUREACCESS_TARGET,
|
|
SCREEN_WIDTH, SCREEN_HEIGHT);
|
|
|
|
SDL_SetTextureBlendMode(_texture, SDL_BLENDMODE_BLEND);
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////
|
|
// Curl callback function
|
|
size_t dashboard::panel::weather::curl_callback(void* contents, size_t size,
|
|
size_t nmemb, void* userp){
|
|
((std::string*)userp)->append((char*)contents, size * nmemb);
|
|
return size * nmemb;
|
|
}
|