dashboard/src/panel/weather.cpp

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