use http json api for weather

This commit is contained in:
Tyler Perkins 2021-12-22 18:27:55 -05:00
parent 6946031f5c
commit 55cd63dff2
4 changed files with 266 additions and 19 deletions

View File

@ -47,8 +47,26 @@ size_t FONT_LOCATIONS_LENGTH = sizeof(FONT_LOCATIONS)/sizeof(FONT_LOCATIONS[0]);
// const FONT_SIZE _font_size;
//};
const FONT_SIZE_STRING CONST_STRINGS[] = {
//Weather strings
//Overlay strings
{ "Weather", { "Roboto_Mono/RobotoMono-Medium.ttf", 50 } },
{ "Wireless", { "Roboto_Mono/RobotoMono-Medium.ttf", 50 } },
//Weather strings
{ "Clear Skies", { "Roboto_Mono/RobotoMono-Medium.ttf", 50 } },
{ "Slightly cloudy", { "Roboto_Mono/RobotoMono-Medium.ttf", 50 } },
{ "Moderately cloudy", { "Roboto_Mono/RobotoMono-Medium.ttf", 50 } },
{ "Very cloudy", { "Roboto_Mono/RobotoMono-Medium.ttf", 50 } },
{ "Very humid", { "Roboto_Mono/RobotoMono-Medium.ttf", 50 } },
{ "Light rain", { "Roboto_Mono/RobotoMono-Medium.ttf", 50 } },
{ "Rain", { "Roboto_Mono/RobotoMono-Medium.ttf", 50 } },
{ "Overcast with showers", { "Roboto_Mono/RobotoMono-Medium.ttf", 50 } },
{ "Moderate showers", { "Roboto_Mono/RobotoMono-Medium.ttf", 50 } },
{ "Light snow", { "Roboto_Mono/RobotoMono-Medium.ttf", 50 } },
{ "Moderate snow", { "Roboto_Mono/RobotoMono-Medium.ttf", 50 } },
{ "Rain and snow", { "Roboto_Mono/RobotoMono-Medium.ttf", 50 } },
{ "Currently,", { "Roboto_Mono/RobotoMono-Medium.ttf", 50 } },
{ "Tommorow,", { "Roboto_Mono/RobotoMono-Medium.ttf", 50 } },
{ "Day after,", { "Roboto_Mono/RobotoMono-Medium.ttf", 50 } },
};
size_t CONST_STRINGS_LENGTH = sizeof(CONST_STRINGS)/sizeof(CONST_STRINGS[0]);

View File

@ -19,8 +19,32 @@ weather::weather(){
_update_interval = std::chrono::milliseconds{WEATHER_UPDATE_INTERVAL};
_texture = nullptr;
_title = WEATHER_TITLE;
//let set to default, will make it so it updates the texture ASAP
//_last_update;
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(){
@ -65,19 +89,49 @@ void weather::update() {
_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
current_desc = "CURRENT DESC PLACEHOLDER";
tommorow_desc = "TOMMOROW DESC PLACEHOLDER";
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
// _rss
// 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());
@ -87,24 +141,100 @@ void weather::update_texture(){
board::getImage("sky.png"), NULL, NULL);
//current weather
tgt.y = 50;
TTF_SizeText(board::getFont({ "Roboto_Mono/RobotoMono-Medium.ttf", 50 }),
current_desc.c_str(),
"Currently,",
&tgt.w, &tgt.h);
tgt.x = SCREEN_WIDTH / 2 - (tgt.w / 2);
tgt.y = SCREEN_HEIGHT / 2 - (tgt.h / 2);
tgt.x = (SCREEN_WIDTH / 2) - (tgt.w / 2);
SDL_RenderCopy(board::getRenderer(),
board::getString(current_desc.c_str(),
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_desc.c_str(),
"Tommorow,",
&tgt.w, &tgt.h);
tgt.x = SCREEN_WIDTH / 2 - (tgt.w / 2);
tgt.y = SCREEN_HEIGHT / 2 - (tgt.h / 2) + 50;
tgt.y = (3*SCREEN_HEIGHT / 4) - (tgt.h / 2);
tgt.x = (SCREEN_WIDTH / 6) - (tgt.w / 2);
SDL_RenderCopy(board::getRenderer(),
board::getString(tommorow_desc.c_str(),
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);
//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);
SDL_SetRenderTarget(board::getRenderer(), NULL);
}
@ -123,3 +253,11 @@ void weather::initTexture(){
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;
}

View File

@ -14,8 +14,13 @@
#include <SDL2/SDL_image.h>
#include <SDL2/SDL_ttf.h>
#include <curl/curl.h>
#include "../util/rapidjson/document.h"
#include <iostream>
#include <string>
#include <unordered_map>
#include <utility>
namespace dashboard::panel {
class weather : public panel {
@ -23,16 +28,30 @@ namespace dashboard::panel {
weather();
~weather();
void draw();
static size_t curl_callback(void*, size_t, size_t, void*);
void draw();
private:
void update();
void update_texture();
void initTexture();
std::string current_desc;
std::string tommorow_desc;
static constexpr bool TODAY = true;
static constexpr bool TOMMOROW = false;
std::unordered_map<std::string,
std::pair<std::string, std::string>> weather_string;
std::pair<std::string, std::string>* weather_today;
std::pair<std::string, std::string>* weather_tommorow;
std::pair<std::string, std::string>* weather_day_after;
short temp_today;
short temp_tommorow;
short temp_day_after;
CURL* api_curl;
std::string json_string;
rapidjson::Document json_doc;
std::chrono::time_point<std::chrono::high_resolution_clock> _last_update;
std::chrono::milliseconds _update_interval;

View File

@ -6,13 +6,16 @@
#pragma once
#include <utility>
#include <string>
namespace dashboard::panel {
//This will be displayed at the top left on the status bar. Set to a blank
//string to not show anything
constexpr char WEATHER_TITLE[] = "Weather";
//New York RSS feed
static const char* WEATHER_URL_SOURCE = "http://rss.accuweather.com/rss/liveweather_rss.asp?locCode=10007";
static const char* WEATHER_URL_SOURCE = "https://www.7timer.info/bin/civil.php?lon=41.13&lat=-81.48&unit=british&output=json&tzshift=0";
//Default time the slide is shown on screen, in ms
//Default 5s
@ -22,4 +25,73 @@ namespace dashboard::panel {
//Default 1 hour
constexpr size_t WEATHER_UPDATE_INTERVAL = 3600000;
//Display temperatures in metric?
//Default false
constexpr bool WEATHER_METRIC = false;
//The following are all of the strings that will be shown for each state of
//weather, along with the image that will be shown
//The struct is of form {WEATHER_STRING, WEATHER_IMAGE}
//with weather string being the string shown on screen, and weather image
//being the name of the preloaded image file to be shown. It is best that
//these images be square.
const std::pair<std::string, std::string> WEATHER_CLEAR_DAY =
{"Clear skies", "clearday.png"};
const std::pair<std::string, std::string> WEATHER_CLEAR_NIGHT =
{"Clear skies", "clearnight.png"};
const std::pair<std::string, std::string> WEATHER_PCLOUDY_DAY =
{"Slightly cloudy", "pcloudyday.png"};
const std::pair<std::string, std::string> WEATHER_PCLOUDY_NIGHT =
{"Slightly cloudy", "pcloudynight.png"};
const std::pair<std::string, std::string> WEATHER_MCLOUDY_DAY =
{"Moderately cloudy", "mcloudyday.png"};
const std::pair<std::string, std::string> WEATHER_MCLOUDY_NIGHT =
{"Moderately cloudy", "mcloudynight.png"};
const std::pair<std::string, std::string> WEATHER_CLOUDY_DAY =
{"Very cloudy", "cloudyday.png"};
const std::pair<std::string, std::string> WEATHER_CLOUDY_NIGHT =
{"Very cloudy", "cloudynight.png"};
const std::pair<std::string, std::string> WEATHER_HUMID_DAY =
{"Very humid", "humidday.png"};
const std::pair<std::string, std::string> WEATHER_HUMID_NIGHT =
{"Very humid", "humidnight.png"};
const std::pair<std::string, std::string> WEATHER_LRAIN_DAY =
{"Light rain", "lrainday.png"};
const std::pair<std::string, std::string> WEATHER_LRAIN_NIGHT =
{"Light rain", "lrainnight.png"};
const std::pair<std::string, std::string> WEATHER_RAIN_DAY =
{"Rain", "rainday.png"};
const std::pair<std::string, std::string> WEATHER_RAIN_NIGHT =
{"Rain", "rainnight.png"};
const std::pair<std::string, std::string> WEATHER_OSHOWER_DAY =
{"Overcast with showers", "oshowerday.png"};
const std::pair<std::string, std::string> WEATHER_OSHOWER_NIGHT =
{"Overcast with showers", "oshowernight.png"};
const std::pair<std::string, std::string> WEATHER_ISHOWER_DAY =
{"Moderate showers", "ishowerday.png"};
const std::pair<std::string, std::string> WEATHER_ISHOWER_NIGHT =
{"Moderate showers", "ishowernight.png"};
const std::pair<std::string, std::string> WEATHER_LSNOW_DAY =
{"Light snow", "lsnowday.png"};
const std::pair<std::string, std::string> WEATHER_LSNOW_NIGHT =
{"Light snow", "lsnownight.png"};
const std::pair<std::string, std::string> WEATHER_SNOW_DAY =
{"Moderate snow", "snowday.png"};
const std::pair<std::string, std::string> WEATHER_SNOW_NIGHT =
{"Moderate snow", "snownight.png"};
const std::pair<std::string, std::string> WEATHER_RAINSNOW_DAY =
{"Rain and snow", "rainsnowday.png"};
const std::pair<std::string, std::string> WEATHER_RAINSNOW_NIGHT =
{"Rain and snow", "rainsnownight.png"};
}