mirror of
https://github.com/Clortox/dashboard.git
synced 2024-12-27 13:38:00 +00:00
Compare commits
10 Commits
55f68ac3cb
...
998f355460
Author | SHA1 | Date | |
---|---|---|---|
|
998f355460 | ||
|
cbcba7d143 | ||
|
4e513a86d8 | ||
|
fed9d23ed8 | ||
|
d857ae85cf | ||
|
1d8fa2600c | ||
|
9a2cf809ed | ||
|
9018d83868 | ||
|
05ae49976b | ||
|
5f06845b1c |
3
.gitignore
vendored
3
.gitignore
vendored
@ -13,3 +13,6 @@ src/config.hpp
|
|||||||
|
|
||||||
#ignore wifi image
|
#ignore wifi image
|
||||||
img/wifi.png
|
img/wifi.png
|
||||||
|
|
||||||
|
#ignore json in tests
|
||||||
|
tests/*.json
|
||||||
|
@ -66,3 +66,10 @@ Things you need to implement as a panel creator
|
|||||||
- `const_resources`
|
- `const_resources`
|
||||||
|
|
||||||
And be sure to inheret from dashboard::panel !
|
And be sure to inheret from dashboard::panel !
|
||||||
|
|
||||||
|
FAQ
|
||||||
|
===
|
||||||
|
|
||||||
|
- I wrote my pannel, yet i keep seeing that SCREEN_WIDTH, SCREEN_HEIGHT,
|
||||||
|
board::*, etc are not defined
|
||||||
|
- Be sure to add `#include "../board.hpp"` at the end of your mypanel.hpp
|
||||||
|
@ -2,20 +2,21 @@ dashboard
|
|||||||
=========
|
=========
|
||||||
|
|
||||||
My dashboard, for my house. Display RSS feeds and other custom bits of info via
|
My dashboard, for my house. Display RSS feeds and other custom bits of info via
|
||||||
direct SDL2 calls.
|
direct SDL2 calls.
|
||||||
|
|
||||||
Features/TODO
|
Features/TODO
|
||||||
=============
|
=============
|
||||||
|
|
||||||
- (DONE) Write straight to framebuffer (sdl2)
|
- (DONE) Write straight to framebuffer (sdl2)
|
||||||
- (DONE) Display Weather ~~rss~~ json feed
|
- (DONE) Display Weather ~~rss~~ json feed
|
||||||
- Get UV Data from openUV
|
- Get UV Data from openUV
|
||||||
- (DONE) Display Wifi qrcode
|
- (DONE) Display Wifi qrcode
|
||||||
- Get wifispeed and number of clients from home assistant
|
- Get wifispeed and number of clients from home assistant
|
||||||
- (DONE) Display plex currently playing
|
- (DONE) Display plex currently playing
|
||||||
- Display camera feed
|
- Display camera feed
|
||||||
- Integrate with Home assistant data (New panel)
|
- Integrate with Home assistant data (New panel)
|
||||||
- https://developers.home-assistant.io/docs/api/rest/
|
- https://developers.home-assistant.io/docs/api/rest/
|
||||||
|
- (DONE) Presence
|
||||||
- Integrate with octoprint
|
- Integrate with octoprint
|
||||||
|
|
||||||
Depends on
|
Depends on
|
||||||
|
@ -10,10 +10,12 @@
|
|||||||
// A list of all panels to be displayed, in order
|
// A list of all panels to be displayed, in order
|
||||||
dashboard::panel::panel* PANELS[] = {
|
dashboard::panel::panel* PANELS[] = {
|
||||||
//new dashboard::panel::sample_panel(),
|
//new dashboard::panel::sample_panel(),
|
||||||
|
new dashboard::panel::homeassistant(),
|
||||||
new dashboard::panel::plex(),
|
new dashboard::panel::plex(),
|
||||||
new dashboard::panel::weather(),
|
new dashboard::panel::weather(),
|
||||||
new dashboard::panel::wifi(),
|
new dashboard::panel::wifi(),
|
||||||
};
|
};
|
||||||
|
|
||||||
size_t PANELS_LENGTH = sizeof(PANELS)/sizeof(PANELS[0]);
|
size_t PANELS_LENGTH = sizeof(PANELS)/sizeof(PANELS[0]);
|
||||||
|
|
||||||
// OVERLAY
|
// OVERLAY
|
||||||
@ -49,7 +51,8 @@ const char* IMAGE_LOCATIONS[] = {
|
|||||||
|
|
||||||
//plex
|
//plex
|
||||||
"plex_background.jpg",
|
"plex_background.jpg",
|
||||||
|
|
||||||
|
//homeassistant
|
||||||
};
|
};
|
||||||
size_t IMAGE_LOCATIONS_LENGTH = sizeof(IMAGE_LOCATIONS)/sizeof(IMAGE_LOCATIONS[0]);
|
size_t IMAGE_LOCATIONS_LENGTH = sizeof(IMAGE_LOCATIONS)/sizeof(IMAGE_LOCATIONS[0]);
|
||||||
|
|
||||||
@ -76,6 +79,7 @@ const FONT_SIZE_STRING CONST_STRINGS[] = {
|
|||||||
{ "Weather", { "Roboto_Mono/RobotoMono-Medium.ttf", 50 } },
|
{ "Weather", { "Roboto_Mono/RobotoMono-Medium.ttf", 50 } },
|
||||||
{ "Wireless", { "Roboto_Mono/RobotoMono-Medium.ttf", 50 } },
|
{ "Wireless", { "Roboto_Mono/RobotoMono-Medium.ttf", 50 } },
|
||||||
{ "Plex", { "Roboto_Mono/RobotoMono-Medium.ttf", 50} },
|
{ "Plex", { "Roboto_Mono/RobotoMono-Medium.ttf", 50} },
|
||||||
|
{ "Homeassistant", { "Roboto_Mono/RobotoMono-Medium.ttf", 50} },
|
||||||
//sample panel
|
//sample panel
|
||||||
//{ "Sample Panel", { "Roboto_Mono/RobotoMono-Medium.ttf", 50} },
|
//{ "Sample Panel", { "Roboto_Mono/RobotoMono-Medium.ttf", 50} },
|
||||||
|
|
||||||
@ -101,5 +105,7 @@ const FONT_SIZE_STRING CONST_STRINGS[] = {
|
|||||||
{ "Playing", {"Roboto_Mono/RobotoMono-Medium.ttf", 28} },
|
{ "Playing", {"Roboto_Mono/RobotoMono-Medium.ttf", 28} },
|
||||||
{ "Top Users", {"Roboto_Mono/RobotoMono-Medium.ttf", 50} },
|
{ "Top Users", {"Roboto_Mono/RobotoMono-Medium.ttf", 50} },
|
||||||
|
|
||||||
|
//Home assistant
|
||||||
|
{ "Home", {"Roboto_Mono/RobotoMono-Medium.ttf", 50} },
|
||||||
};
|
};
|
||||||
size_t CONST_STRINGS_LENGTH = sizeof(CONST_STRINGS)/sizeof(CONST_STRINGS[0]);
|
size_t CONST_STRINGS_LENGTH = sizeof(CONST_STRINGS)/sizeof(CONST_STRINGS[0]);
|
||||||
|
@ -79,6 +79,7 @@ constexpr int IMG_FLAGS = 0
|
|||||||
#include "panel/def_overlay.hpp"
|
#include "panel/def_overlay.hpp"
|
||||||
#include "panel/wifi.hpp"
|
#include "panel/wifi.hpp"
|
||||||
#include "panel/plex.hpp"
|
#include "panel/plex.hpp"
|
||||||
|
#include "panel/homeassistant.hpp"
|
||||||
//uncomment this to use the sample panel
|
//uncomment this to use the sample panel
|
||||||
//#include "panel/sample_panel.hpp"
|
//#include "panel/sample_panel.hpp"
|
||||||
extern dashboard::panel::panel* PANELS[];
|
extern dashboard::panel::panel* PANELS[];
|
||||||
|
@ -16,7 +16,7 @@ int main(int argc, char** argv){
|
|||||||
dashboard::board _board(false);
|
dashboard::board _board(false);
|
||||||
|
|
||||||
if(_board.init() != 0){
|
if(_board.init() != 0){
|
||||||
std::cerr << "Due to errors, " << argv[0]
|
std::cerr << "Due to errors, " << argv[0]
|
||||||
<< " was unable to start, quitting!" << std::endl;
|
<< " was unable to start, quitting!" << std::endl;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
223
src/panel/homeassistant.cpp
Normal file
223
src/panel/homeassistant.cpp
Normal file
@ -0,0 +1,223 @@
|
|||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Tyler Perkins
|
||||||
|
// 14-1-22
|
||||||
|
// homeassistant panel
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "homeassistant.hpp"
|
||||||
|
#include "homeassistant_config.hpp"
|
||||||
|
|
||||||
|
using namespace dashboard::panel;
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Constructors ///////////////////////////////////////////////////////////////
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
homeassistant::homeassistant(){
|
||||||
|
std::cerr << "HOMEASSISTANT CONSTRUCTOR\n";
|
||||||
|
_time_on_screen = HOMEASSISTANT_DEFAULT_ON_SCREEN_TIME;
|
||||||
|
_update_interval = std::chrono::milliseconds{HOMEASSISTANT_UPDATE_INTERVAL};
|
||||||
|
_texture = nullptr;
|
||||||
|
_title = HOMEASSISTANT_TITLE;
|
||||||
|
|
||||||
|
std::string api_string = "Authorization: Bearer ";
|
||||||
|
api_string += HOMEASSISTANT_APIKEY;
|
||||||
|
|
||||||
|
headers = NULL;
|
||||||
|
headers = curl_slist_append(headers, api_string.c_str());
|
||||||
|
headers = curl_slist_append(headers, "Content-Type: application/json");
|
||||||
|
|
||||||
|
api_string.clear();
|
||||||
|
|
||||||
|
api_curl = curl_easy_init();
|
||||||
|
curl_easy_setopt(api_curl, CURLOPT_HTTPHEADER, headers);
|
||||||
|
curl_easy_setopt(api_curl, CURLOPT_URL, HOMEASSISTANT_URL);
|
||||||
|
curl_easy_setopt(api_curl, CURLOPT_WRITEFUNCTION,
|
||||||
|
dashboard::panel::homeassistant::curl_callback);
|
||||||
|
curl_easy_setopt(api_curl, CURLOPT_WRITEDATA, &json_string);
|
||||||
|
//Write request string in update function
|
||||||
|
}
|
||||||
|
|
||||||
|
homeassistant::~homeassistant(){
|
||||||
|
std::cerr << "HOMEASSISTANT DECONSTRUCTOR\n";
|
||||||
|
if(_texture != nullptr){
|
||||||
|
SDL_DestroyTexture(_texture);
|
||||||
|
}
|
||||||
|
if(api_curl != nullptr){
|
||||||
|
curl_easy_cleanup(api_curl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Draw function //////////////////////////////////////////////////////////////
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void homeassistant::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 homeassistant::update(){
|
||||||
|
std::cerr << "HOMEASSISTANT::UPDATE\n";
|
||||||
|
_last_update = std::chrono::high_resolution_clock::now();
|
||||||
|
|
||||||
|
//perform request
|
||||||
|
curl_easy_perform(api_curl);
|
||||||
|
|
||||||
|
//parse the result
|
||||||
|
json_doc.Parse(json_string.c_str());
|
||||||
|
|
||||||
|
//update internal state
|
||||||
|
for(rapidjson::SizeType i = 0; i < json_doc.Size(); i++){
|
||||||
|
|
||||||
|
//if is a person entry
|
||||||
|
if(strstr(json_doc[i]["entity_id"].GetString(), "person.") != NULL){
|
||||||
|
//get the last changed date and convert to a tm
|
||||||
|
std::string format_str = json_doc[i]["last_changed"].GetString();
|
||||||
|
std::time_t t = datestringToTm(format_str);
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << std::put_time(std::localtime(&t), "%b %e, %I:%M %p");
|
||||||
|
|
||||||
|
struct home_entry entry = {
|
||||||
|
json_doc[i]["attributes"]["friendly_name"].GetString(),
|
||||||
|
strcmp(json_doc[i]["state"].GetString(), "home") == 0 ? true : false,
|
||||||
|
ss.str(),
|
||||||
|
};
|
||||||
|
|
||||||
|
home_entries.push_back(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO other entries from general home assistant?
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
json_string.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////
|
||||||
|
// Update the texture that is being
|
||||||
|
// displayed, based on data grabed from json
|
||||||
|
void homeassistant::update_texture(){
|
||||||
|
std::cerr << "HOMEASSISTANT::UPDATE_TEXTURE\n";
|
||||||
|
|
||||||
|
SDL_Rect tgt;
|
||||||
|
|
||||||
|
SDL_SetRenderTarget(board::getRenderer(), _texture);
|
||||||
|
SDL_RenderClear(board::getRenderer());
|
||||||
|
|
||||||
|
constexpr int GAP_SIZE = 10;
|
||||||
|
|
||||||
|
//draw each name and time last seen
|
||||||
|
{
|
||||||
|
for(size_t i = 0; i < home_entries.size(); ++i){
|
||||||
|
tgt.x = (SCREEN_WIDTH / (2 * home_entries.size()))
|
||||||
|
+ i * (SCREEN_WIDTH / home_entries.size());
|
||||||
|
tgt.y = DEF_OVERLAY_BAR_HEIGHT + GAP_SIZE;
|
||||||
|
TTF_SizeText(board::getFont( {"Roboto_Mono/RobotoMono-Medium.ttf", 50} ),
|
||||||
|
home_entries[i].name.c_str(),
|
||||||
|
&tgt.w, &tgt.h);
|
||||||
|
|
||||||
|
tgt.x -= tgt.w / 2;
|
||||||
|
|
||||||
|
SDL_RenderCopy(board::getRenderer(),
|
||||||
|
board::getString(home_entries[i].name,
|
||||||
|
{ "Roboto_Mono/RobotoMono-Medium.ttf", 50 }),
|
||||||
|
NULL, &tgt);
|
||||||
|
|
||||||
|
//down a new line
|
||||||
|
tgt.y += tgt.h + GAP_SIZE;
|
||||||
|
tgt.x += tgt.w / 2;
|
||||||
|
|
||||||
|
std::string home = "";
|
||||||
|
|
||||||
|
//if is home
|
||||||
|
if(home_entries[i].home){
|
||||||
|
home = "Home";
|
||||||
|
} else {
|
||||||
|
home = home_entries[i].time;
|
||||||
|
}
|
||||||
|
|
||||||
|
TTF_SizeText(board::getFont( {"Roboto_Mono/RobotoMono-Medium.ttf", 50} ),
|
||||||
|
home.c_str(),
|
||||||
|
&tgt.w, &tgt.h);
|
||||||
|
|
||||||
|
tgt.x -= tgt.w / 2;
|
||||||
|
|
||||||
|
SDL_RenderCopy(board::getRenderer(),
|
||||||
|
board::getString(home,
|
||||||
|
{ "Roboto_Mono/RobotoMono-Medium.ttf", 50 }),
|
||||||
|
NULL, &tgt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
home_entries.clear();
|
||||||
|
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 homeassistant::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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////
|
||||||
|
// Convert the homeassistant string
|
||||||
|
// format to a tm object
|
||||||
|
std::time_t homeassistant::datestringToTm(const std::string& date_string){
|
||||||
|
int year = 0, month = 0, day = 0, hour = 0, minuite = 0, second = 0;
|
||||||
|
|
||||||
|
std::tm tm_tmp{};
|
||||||
|
|
||||||
|
if(sscanf(date_string.c_str(), "%4d-%2d-%2dT%2d:%2d:%2d",
|
||||||
|
&year, &month, &day, &hour, &minuite, &second) == 6){
|
||||||
|
tm_tmp.tm_year = year - 1900;
|
||||||
|
tm_tmp.tm_mon = month - 1;
|
||||||
|
tm_tmp.tm_mday = day;
|
||||||
|
tm_tmp.tm_hour = hour;
|
||||||
|
tm_tmp.tm_min = minuite;
|
||||||
|
tm_tmp.tm_sec = second;
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::mktime(&tm_tmp) - timezone;
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////
|
||||||
|
// Curl callback function
|
||||||
|
size_t dashboard::panel::homeassistant::curl_callback(void* contents, size_t size,
|
||||||
|
size_t nmemb, void* userp){
|
||||||
|
((std::string*)userp)->append((char*)contents, size * nmemb);
|
||||||
|
return size * nmemb;
|
||||||
|
}
|
59
src/panel/homeassistant.hpp
Normal file
59
src/panel/homeassistant.hpp
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Tyler Perkins
|
||||||
|
// 14-1-22
|
||||||
|
// Home assistant panel
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "panel.hpp"
|
||||||
|
|
||||||
|
#include <SDL.h>
|
||||||
|
#include <SDL2/SDL_image.h>
|
||||||
|
#include <SDL2/SDL_ttf.h>
|
||||||
|
|
||||||
|
#include <curl/curl.h>
|
||||||
|
#include "../util/rapidjson/document.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
#include <string.h>
|
||||||
|
#include <chrono>
|
||||||
|
#include <vector>
|
||||||
|
#include <iomanip>
|
||||||
|
|
||||||
|
namespace dashboard::panel {
|
||||||
|
class homeassistant : public panel {
|
||||||
|
public:
|
||||||
|
homeassistant();
|
||||||
|
~homeassistant();
|
||||||
|
|
||||||
|
static size_t curl_callback(void*, size_t, size_t, void*);
|
||||||
|
|
||||||
|
void draw();
|
||||||
|
private:
|
||||||
|
void update();
|
||||||
|
void update_texture();
|
||||||
|
void initTexture();
|
||||||
|
|
||||||
|
std::time_t datestringToTm(const std::string&);
|
||||||
|
|
||||||
|
struct home_entry {
|
||||||
|
std::string name;
|
||||||
|
bool home;
|
||||||
|
std::string time;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<home_entry> home_entries;
|
||||||
|
|
||||||
|
CURL* api_curl;
|
||||||
|
struct curl_slist *headers;
|
||||||
|
std::string json_string;
|
||||||
|
rapidjson::Document json_doc;
|
||||||
|
|
||||||
|
std::chrono::time_point<std::chrono::high_resolution_clock> _last_update;
|
||||||
|
std::chrono::milliseconds _update_interval;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "../board.hpp"
|
31
src/panel/homeassistant_config.hpp
Normal file
31
src/panel/homeassistant_config.hpp
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Tyler Perkins
|
||||||
|
// 14-1-22
|
||||||
|
// homeassistant configuration
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "def_overlay_config.hpp"
|
||||||
|
|
||||||
|
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 HOMEASSISTANT_TITLE[] = "Home assistant";
|
||||||
|
|
||||||
|
//API key, you can get this in homeassistant under your profile
|
||||||
|
constexpr char HOMEASSISTANT_APIKEY[] = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiIxYTNhNDhhYTBlZDM0MjkyOTk5OWZhNGVjZGRjMGUwMCIsImlhdCI6MTY0MjE4NDU0MCwiZXhwIjoxOTU3NTQ0NTQwfQ.Zdy7-ZwX0HuwhmUGeLhF5XCluotsKmpDqmi5o-hQZCc";
|
||||||
|
|
||||||
|
//This API endpoint. Sub the IP with the IP of the homeassistant server on
|
||||||
|
//your network. Be sure to enable the RESTful API in homeassistant's
|
||||||
|
//configuration.yaml
|
||||||
|
constexpr char HOMEASSISTANT_URL[] = "http://192.168.1.104:8123/api/states";
|
||||||
|
|
||||||
|
//Default time the slide is shown on screen, in ms
|
||||||
|
//Default 15s
|
||||||
|
constexpr size_t HOMEASSISTANT_DEFAULT_ON_SCREEN_TIME = 15000;
|
||||||
|
|
||||||
|
//How long should we wait between updates? in ms
|
||||||
|
//Default 15
|
||||||
|
constexpr size_t HOMEASSISTANT_UPDATE_INTERVAL = 15000;
|
||||||
|
}
|
@ -50,7 +50,7 @@ void plex::draw(){
|
|||||||
}
|
}
|
||||||
|
|
||||||
//check if its time to update
|
//check if its time to update
|
||||||
if((std::chrono::high_resolution_clock::now() - _last_update)
|
if((std::chrono::high_resolution_clock::now() - _last_update)
|
||||||
> _update_interval){
|
> _update_interval){
|
||||||
update();
|
update();
|
||||||
|
|
||||||
@ -84,13 +84,13 @@ void plex::update(){
|
|||||||
|
|
||||||
for(short i = 0; i < 4; ++i){
|
for(short i = 0; i < 4; ++i){
|
||||||
entries.at(i) = {
|
entries.at(i) = {
|
||||||
truncate(curr_entry[i]["friendly_name"].GetString(),
|
truncate(curr_entry[i]["friendly_name"].GetString(),
|
||||||
PLEX_MAX_STRING_LENGTH),
|
PLEX_MAX_STRING_LENGTH),
|
||||||
truncate(curr_entry[i]["ip_address"].GetString(),
|
truncate(curr_entry[i]["ip_address"].GetString(),
|
||||||
PLEX_MAX_STRING_LENGTH),
|
PLEX_MAX_STRING_LENGTH),
|
||||||
truncate(curr_entry[i]["title"].GetString(),
|
truncate(curr_entry[i]["title"].GetString(),
|
||||||
PLEX_MAX_STRING_LENGTH),
|
PLEX_MAX_STRING_LENGTH),
|
||||||
truncate(curr_entry[i]["state"].IsNull() ? "Historical" : "Playing",
|
truncate(curr_entry[i]["state"].IsNull() ? "Historical" : "Playing",
|
||||||
PLEX_MAX_STRING_LENGTH),
|
PLEX_MAX_STRING_LENGTH),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -129,7 +129,7 @@ void plex::update(){
|
|||||||
json_doc.Parse(json_string.c_str());
|
json_doc.Parse(json_string.c_str());
|
||||||
|
|
||||||
friendly_name = truncate(json_doc["response"]["data"].GetString(), PLEX_MAX_STRING_LENGTH - 10);
|
friendly_name = truncate(json_doc["response"]["data"].GetString(), PLEX_MAX_STRING_LENGTH - 10);
|
||||||
|
|
||||||
json_string.clear();
|
json_string.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -144,13 +144,13 @@ void plex::update_texture(){
|
|||||||
//save the old colors
|
//save the old colors
|
||||||
SDL_GetRenderDrawColor(board::getRenderer(), &o_red,
|
SDL_GetRenderDrawColor(board::getRenderer(), &o_red,
|
||||||
&o_green, &o_blue, &o_alpha);
|
&o_green, &o_blue, &o_alpha);
|
||||||
|
|
||||||
SDL_SetRenderTarget(board::getRenderer(), _texture);
|
SDL_SetRenderTarget(board::getRenderer(), _texture);
|
||||||
SDL_RenderClear(board::getRenderer());
|
SDL_RenderClear(board::getRenderer());
|
||||||
|
|
||||||
//set the new color
|
//set the new color
|
||||||
SDL_SetRenderDrawColor(board::getRenderer(),
|
SDL_SetRenderDrawColor(board::getRenderer(),
|
||||||
PLEX_BGBOX_RED, PLEX_BGBOX_GREEN,
|
PLEX_BGBOX_RED, PLEX_BGBOX_GREEN,
|
||||||
PLEX_BGBOX_BLUE, PLEX_BGBOX_ALPHA);
|
PLEX_BGBOX_BLUE, PLEX_BGBOX_ALPHA);
|
||||||
|
|
||||||
//background image
|
//background image
|
||||||
@ -411,8 +411,8 @@ void plex::update_texture(){
|
|||||||
void plex::initTexture(){
|
void plex::initTexture(){
|
||||||
if(_texture == nullptr){
|
if(_texture == nullptr){
|
||||||
_texture = SDL_CreateTexture(board::getRenderer(),
|
_texture = SDL_CreateTexture(board::getRenderer(),
|
||||||
SDL_PIXELFORMAT_RGBA8888,
|
SDL_PIXELFORMAT_RGBA8888,
|
||||||
SDL_TEXTUREACCESS_TARGET,
|
SDL_TEXTUREACCESS_TARGET,
|
||||||
SCREEN_WIDTH, SCREEN_HEIGHT);
|
SCREEN_WIDTH, SCREEN_HEIGHT);
|
||||||
|
|
||||||
SDL_SetTextureBlendMode(_texture, SDL_BLENDMODE_BLEND);
|
SDL_SetTextureBlendMode(_texture, SDL_BLENDMODE_BLEND);
|
||||||
|
@ -39,7 +39,6 @@ namespace dashboard::panel {
|
|||||||
CURL* api_curl;
|
CURL* api_curl;
|
||||||
std::string json_string;
|
std::string json_string;
|
||||||
rapidjson::Document json_doc;
|
rapidjson::Document json_doc;
|
||||||
|
|
||||||
struct plex_entry {
|
struct plex_entry {
|
||||||
std::string friendly_name;
|
std::string friendly_name;
|
||||||
std::string ip_address;
|
std::string ip_address;
|
||||||
|
@ -13,10 +13,10 @@ namespace dashboard::panel {
|
|||||||
//string to not show anything
|
//string to not show anything
|
||||||
constexpr char PLEX_TITLE[] = "Plex";
|
constexpr char PLEX_TITLE[] = "Plex";
|
||||||
|
|
||||||
//Tautili endpoint
|
//Tautili endpoint
|
||||||
constexpr char PLEX_URL_SOURCE_HISTORY[] = "http://192.168.1.104:8181/api/v2?apikey=64af06e0497342f7a5862462ddbbd309&cmd=get_history&length=5";
|
constexpr char PLEX_URL_SOURCE_HISTORY[] = "http://192.168.1.104:8181/api/v2?apikey=62917cc0bea04aa69cbb85141e312e84&cmd=get_history&length=5";
|
||||||
constexpr char PLEX_URL_SOURCE_NAME[] = "http://192.168.1.104:8181/api/v2?apikey=64af06e0497342f7a5862462ddbbd309&cmd=get_server_friendly_name";
|
constexpr char PLEX_URL_SOURCE_NAME[] = "http://192.168.1.104:8181/api/v2?apikey=62917cc0bea04aa69cbb85141e312e84&cmd=get_server_friendly_name";
|
||||||
constexpr char PLEX_URL_SOURCE_TOP_USERS[] = "http://192.168.1.104:8181/api/v2?apikey=64af06e0497342f7a5862462ddbbd309&cmd=get_plays_by_top_10_users";
|
constexpr char PLEX_URL_SOURCE_TOP_USERS[] = "http://192.168.1.104:8181/api/v2?apikey=62917cc0bea04aa69cbb85141e312e84&cmd=get_plays_by_top_10_users";
|
||||||
|
|
||||||
//How many characters of a show title should we show?
|
//How many characters of a show title should we show?
|
||||||
constexpr size_t PLEX_MAX_STRING_LENGTH = 35;
|
constexpr size_t PLEX_MAX_STRING_LENGTH = 35;
|
||||||
@ -34,5 +34,4 @@ namespace dashboard::panel {
|
|||||||
constexpr uint8_t PLEX_BGBOX_GREEN = 0x66;
|
constexpr uint8_t PLEX_BGBOX_GREEN = 0x66;
|
||||||
constexpr uint8_t PLEX_BGBOX_BLUE = 0x66;
|
constexpr uint8_t PLEX_BGBOX_BLUE = 0x66;
|
||||||
constexpr uint8_t PLEX_BGBOX_ALPHA = 0x99;
|
constexpr uint8_t PLEX_BGBOX_ALPHA = 0x99;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -36,57 +36,57 @@ namespace dashboard::panel {
|
|||||||
//with weather string being the string shown on screen, and 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
|
//being the name of the preloaded image file to be shown. It is best that
|
||||||
//these images be square.
|
//these images be square.
|
||||||
const std::pair<std::string, std::string> WEATHER_CLEAR_DAY =
|
const std::pair<std::string, std::string> WEATHER_CLEAR_DAY =
|
||||||
{"Clear skies", "clearday.png"};
|
{"Clear skies", "clearday.png"};
|
||||||
const std::pair<std::string, std::string> WEATHER_CLEAR_NIGHT =
|
const std::pair<std::string, std::string> WEATHER_CLEAR_NIGHT =
|
||||||
{"Clear skies", "clearnight.png"};
|
{"Clear skies", "clearnight.png"};
|
||||||
|
|
||||||
const std::pair<std::string, std::string> WEATHER_PCLOUDY_DAY =
|
const std::pair<std::string, std::string> WEATHER_PCLOUDY_DAY =
|
||||||
{"Slightly cloudy", "cloudyday.png"};
|
{"Slightly cloudy", "cloudyday.png"};
|
||||||
const std::pair<std::string, std::string> WEATHER_PCLOUDY_NIGHT =
|
const std::pair<std::string, std::string> WEATHER_PCLOUDY_NIGHT =
|
||||||
{"Slightly cloudy", "cloudynight.png"};
|
{"Slightly cloudy", "cloudynight.png"};
|
||||||
|
|
||||||
const std::pair<std::string, std::string> WEATHER_MCLOUDY_DAY =
|
const std::pair<std::string, std::string> WEATHER_MCLOUDY_DAY =
|
||||||
{"Moderately cloudy", "cloudyday.png"};
|
{"Moderately cloudy", "cloudyday.png"};
|
||||||
const std::pair<std::string, std::string> WEATHER_MCLOUDY_NIGHT =
|
const std::pair<std::string, std::string> WEATHER_MCLOUDY_NIGHT =
|
||||||
{"Moderately cloudy", "cloudynight.png"};
|
{"Moderately cloudy", "cloudynight.png"};
|
||||||
|
|
||||||
const std::pair<std::string, std::string> WEATHER_CLOUDY_DAY =
|
const std::pair<std::string, std::string> WEATHER_CLOUDY_DAY =
|
||||||
{"Very cloudy", "cloudyday.png"};
|
{"Very cloudy", "cloudyday.png"};
|
||||||
const std::pair<std::string, std::string> WEATHER_CLOUDY_NIGHT =
|
const std::pair<std::string, std::string> WEATHER_CLOUDY_NIGHT =
|
||||||
{"Very cloudy", "cloudynight.png"};
|
{"Very cloudy", "cloudynight.png"};
|
||||||
|
|
||||||
const std::pair<std::string, std::string> WEATHER_HUMID_DAY =
|
const std::pair<std::string, std::string> WEATHER_HUMID_DAY =
|
||||||
{"Very humid", "humidday.png"};
|
{"Very humid", "humidday.png"};
|
||||||
const std::pair<std::string, std::string> WEATHER_HUMID_NIGHT =
|
const std::pair<std::string, std::string> WEATHER_HUMID_NIGHT =
|
||||||
{"Very humid", "humidnight.png"};
|
{"Very humid", "humidnight.png"};
|
||||||
|
|
||||||
const std::pair<std::string, std::string> WEATHER_LRAIN_DAY =
|
const std::pair<std::string, std::string> WEATHER_LRAIN_DAY =
|
||||||
{"Light rain", "lrainday.png"};
|
{"Light rain", "lrainday.png"};
|
||||||
const std::pair<std::string, std::string> WEATHER_LRAIN_NIGHT =
|
const std::pair<std::string, std::string> WEATHER_LRAIN_NIGHT =
|
||||||
{"Light rain", "lrainnight.png"};
|
{"Light rain", "lrainnight.png"};
|
||||||
|
|
||||||
const std::pair<std::string, std::string> WEATHER_RAIN_DAY =
|
const std::pair<std::string, std::string> WEATHER_RAIN_DAY =
|
||||||
{"Rain", "rainday.png"};
|
{"Rain", "rainday.png"};
|
||||||
const std::pair<std::string, std::string> WEATHER_RAIN_NIGHT =
|
const std::pair<std::string, std::string> WEATHER_RAIN_NIGHT =
|
||||||
{"Rain", "rainnight.png"};
|
{"Rain", "rainnight.png"};
|
||||||
|
|
||||||
const std::pair<std::string, std::string> WEATHER_OSHOWER_DAY =
|
const std::pair<std::string, std::string> WEATHER_OSHOWER_DAY =
|
||||||
{"Overcast with showers", "shower.png"};
|
{"Overcast with showers", "shower.png"};
|
||||||
const std::pair<std::string, std::string> WEATHER_OSHOWER_NIGHT =
|
const std::pair<std::string, std::string> WEATHER_OSHOWER_NIGHT =
|
||||||
{"Overcast with showers", "shower.png"};
|
{"Overcast with showers", "shower.png"};
|
||||||
|
|
||||||
const std::pair<std::string, std::string> WEATHER_ISHOWER_DAY =
|
const std::pair<std::string, std::string> WEATHER_ISHOWER_DAY =
|
||||||
{"Moderate showers", "shower.png"};
|
{"Moderate showers", "shower.png"};
|
||||||
const std::pair<std::string, std::string> WEATHER_ISHOWER_NIGHT =
|
const std::pair<std::string, std::string> WEATHER_ISHOWER_NIGHT =
|
||||||
{"Moderate showers", "shower.png"};
|
{"Moderate showers", "shower.png"};
|
||||||
|
|
||||||
const std::pair<std::string, std::string> WEATHER_LSNOW_DAY =
|
const std::pair<std::string, std::string> WEATHER_LSNOW_DAY =
|
||||||
{"Light snow", "snowday.png"};
|
{"Light snow", "snowday.png"};
|
||||||
const std::pair<std::string, std::string> WEATHER_LSNOW_NIGHT =
|
const std::pair<std::string, std::string> WEATHER_LSNOW_NIGHT =
|
||||||
{"Light snow", "snownight.png"};
|
{"Light snow", "snownight.png"};
|
||||||
|
|
||||||
const std::pair<std::string, std::string> WEATHER_SNOW_DAY =
|
const std::pair<std::string, std::string> WEATHER_SNOW_DAY =
|
||||||
{"Moderate snow", "snowday.png"};
|
{"Moderate snow", "snowday.png"};
|
||||||
const std::pair<std::string, std::string> WEATHER_SNOW_NIGHT =
|
const std::pair<std::string, std::string> WEATHER_SNOW_NIGHT =
|
||||||
{"Moderate snow", "snownight.png"};
|
{"Moderate snow", "snownight.png"};
|
||||||
|
@ -19,13 +19,21 @@ wifi::wifi(){
|
|||||||
std::cerr << "WIFI CONSTRUCTOR\n";
|
std::cerr << "WIFI CONSTRUCTOR\n";
|
||||||
_texture = nullptr;
|
_texture = nullptr;
|
||||||
_time_on_screen = WIFI_DEFAULT_TIME_ON_SCREEN;
|
_time_on_screen = WIFI_DEFAULT_TIME_ON_SCREEN;
|
||||||
|
_update_interval = std::chrono::milliseconds{WIFI_UPDATE_INTERVAL};
|
||||||
_title = WIFI_TITLE;
|
_title = WIFI_TITLE;
|
||||||
|
|
||||||
|
api_curl = curl_easy_init();
|
||||||
|
curl_easy_setopt(api_curl, CURLOPT_WRITEFUNCTION,
|
||||||
|
dashboard::panel::wifi::curl_callback);
|
||||||
|
curl_easy_setopt(api_curl, CURLOPT_WRITEDATA, &json_string);
|
||||||
}
|
}
|
||||||
|
|
||||||
wifi::~wifi(){
|
wifi::~wifi(){
|
||||||
std::cerr << "WIFI DECONSTRUCTOR\n";
|
std::cerr << "WIFI DECONSTRUCTOR\n";
|
||||||
if(_texture != nullptr)
|
if(_texture != nullptr)
|
||||||
SDL_DestroyTexture(_texture);
|
SDL_DestroyTexture(_texture);
|
||||||
|
if(api_curl != nullptr)
|
||||||
|
curl_easy_cleanup(api_curl);
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
@ -40,6 +48,14 @@ void wifi::draw(){
|
|||||||
update_texture();
|
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);
|
SDL_RenderCopy(board::getRenderer(), _texture, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,12 +67,91 @@ void wifi::draw(){
|
|||||||
// Update the information of wifi
|
// Update the information of wifi
|
||||||
// This DOES NOT update the display
|
// This DOES NOT update the display
|
||||||
void wifi::update() {
|
void wifi::update() {
|
||||||
//this shows static info on the wifi network, which does need to change
|
std::cerr << "WIFI::UPDATE\n";
|
||||||
//therefore, no update
|
_last_update = std::chrono::high_resolution_clock::now();
|
||||||
|
|
||||||
|
if(WIFI_HOMEASSISTANT){
|
||||||
|
curl_easy_setopt(api_curl, CURLOPT_URL,
|
||||||
|
WIFI_HOMEASSISTANT_URL);
|
||||||
|
std::string api_string = "Authorization: Bearer ";
|
||||||
|
api_string += WIFI_HOMEASSISTANT_APIKEY;
|
||||||
|
|
||||||
|
struct curl_slist *headers;
|
||||||
|
headers = NULL;
|
||||||
|
headers = curl_slist_append(headers, api_string.c_str());
|
||||||
|
headers = curl_slist_append(headers, "Content-Type: application/json");
|
||||||
|
|
||||||
|
curl_easy_setopt(api_curl, CURLOPT_HTTPHEADER, headers);
|
||||||
|
|
||||||
|
api_string.clear();
|
||||||
|
|
||||||
|
//perform request
|
||||||
|
curl_easy_perform(api_curl);
|
||||||
|
|
||||||
|
//parse the result
|
||||||
|
json_doc.Parse(json_string.c_str());
|
||||||
|
|
||||||
|
//update internal state
|
||||||
|
for(rapidjson::SizeType i = 0; i < json_doc.Size(); i++){
|
||||||
|
//if router external IP
|
||||||
|
if(strcmp(json_doc[i]["entity_id"].GetString(),
|
||||||
|
WIFI_HOMEASSISTANT_ROUTER_EXTERNAL_IP) == 0
|
||||||
|
&& WIFI_SHOW_PUBLIC_IP){
|
||||||
|
//store it in public IP field
|
||||||
|
public_ip = "WAN IP: ";
|
||||||
|
public_ip += json_doc[i]["state"].GetString();
|
||||||
|
} //if router WAN status
|
||||||
|
else if (strcmp(json_doc[i]["entity_id"].GetString(),
|
||||||
|
WIFI_HOMEASSISTANT_ROUTER_WAN_STATUS) == 0){
|
||||||
|
if(strcmp(json_doc[i]["state"].GetString(), "Connected") == 0)
|
||||||
|
wan_status = true;
|
||||||
|
else
|
||||||
|
wan_status = false;
|
||||||
|
} //speedtest up
|
||||||
|
else if (strcmp(json_doc[i]["entity_id"].GetString(),
|
||||||
|
WIFI_HOMEASSISTANT_SPEEDTEST_UP) == 0
|
||||||
|
&& WIFI_HOMEASSISTANT_SPEEDTEST){
|
||||||
|
speedtest_up = "Upload: ";
|
||||||
|
speedtest_up += json_doc[i]["state"].GetString();
|
||||||
|
speedtest_up += "Mbps";
|
||||||
|
} //speedtest down
|
||||||
|
else if (strcmp(json_doc[i]["entity_id"].GetString(),
|
||||||
|
WIFI_HOMEASSISTANT_SPEEDTEST_DOWN) == 0
|
||||||
|
&& WIFI_HOMEASSISTANT_SPEEDTEST){
|
||||||
|
speedtest_down = "Download: ";
|
||||||
|
speedtest_down += json_doc[i]["state"].GetString();
|
||||||
|
speedtest_down += "Mbps";
|
||||||
|
} //speedtest ping
|
||||||
|
else if (strcmp(json_doc[i]["entity_id"].GetString(),
|
||||||
|
WIFI_HOMEASSISTANT_SPEEDTEST_PING) == 0
|
||||||
|
&& WIFI_HOMEASSISTANT_SPEEDTEST){
|
||||||
|
speedtest_ping = "Ping: ";
|
||||||
|
speedtest_ping += json_doc[i]["state"].GetString();
|
||||||
|
speedtest_ping += "ms";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//if not using home assistant, grab it via normal method
|
||||||
|
if(WIFI_SHOW_PUBLIC_IP){
|
||||||
|
//get the string from normal url
|
||||||
|
if(!WIFI_HOMEASSISTANT){
|
||||||
|
public_ip = "WAN IP: ";
|
||||||
|
curl_easy_setopt(api_curl, CURLOPT_URL,
|
||||||
|
WIFI_PUBLIC_IP_URL);
|
||||||
|
|
||||||
|
//peform request
|
||||||
|
curl_easy_perform(api_curl);
|
||||||
|
|
||||||
|
//parse the result
|
||||||
|
public_ip += json_string;
|
||||||
|
}
|
||||||
|
//the public IP should have already been grabbed above
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////
|
///////////////////////////////////////
|
||||||
// Update the texture that is being
|
// Update the texture that is being
|
||||||
// displayed. Due to the nature of what
|
// displayed. Due to the nature of what
|
||||||
// is being displayed, this will only
|
// is being displayed, this will only
|
||||||
// ever be called once, as the wifi
|
// ever be called once, as the wifi
|
||||||
@ -110,24 +205,15 @@ void wifi::update_texture(){
|
|||||||
board::getString(password_string.c_str(),
|
board::getString(password_string.c_str(),
|
||||||
{ "Roboto_Mono/RobotoMono-Medium.ttf", 50 }), NULL, &tgt);
|
{ "Roboto_Mono/RobotoMono-Medium.ttf", 50 }), NULL, &tgt);
|
||||||
|
|
||||||
|
tgt.y += tgt.h + 25;
|
||||||
|
TTF_SizeText(board::getFont({ "Roboto_Mono/RobotoMono-Medium.ttf", 50 }),
|
||||||
|
wan_status ? "Internet is up" : "Internet is down; reconnecting", &tgt.w, &tgt.h);
|
||||||
|
SDL_RenderCopy(board::getRenderer(),
|
||||||
|
board::getString(wan_status ? "Internet is up" : "Internet is down; reconnecting",
|
||||||
|
{ "Roboto_Mono/RobotoMono-Medium.ttf", 50 }), NULL, &tgt);
|
||||||
|
|
||||||
//Get public ip address and display it
|
//Get public ip address and display it
|
||||||
if(WIFI_SHOW_PUBLIC_IP){
|
if(WIFI_SHOW_PUBLIC_IP){
|
||||||
std::string public_ip = "WAN IP: ";
|
|
||||||
CURL* curl;
|
|
||||||
curl = curl_easy_init();
|
|
||||||
|
|
||||||
if(curl){
|
|
||||||
CURLcode res;
|
|
||||||
curl_easy_setopt(curl, CURLOPT_URL, WIFI_PUBLIC_IP_URL);
|
|
||||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION,
|
|
||||||
dashboard::panel::wifi::curl_callback);
|
|
||||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &public_ip);
|
|
||||||
res = curl_easy_perform(curl);
|
|
||||||
curl_easy_cleanup(curl);
|
|
||||||
} else {
|
|
||||||
public_ip += "Unkown";
|
|
||||||
}
|
|
||||||
|
|
||||||
tgt.y += tgt.h + 25;
|
tgt.y += tgt.h + 25;
|
||||||
TTF_SizeText(board::getFont({ "Roboto_Mono/RobotoMono-Medium.ttf", 50 }),
|
TTF_SizeText(board::getFont({ "Roboto_Mono/RobotoMono-Medium.ttf", 50 }),
|
||||||
public_ip.c_str(), &tgt.w, &tgt.h);
|
public_ip.c_str(), &tgt.w, &tgt.h);
|
||||||
@ -136,6 +222,29 @@ void wifi::update_texture(){
|
|||||||
{ "Roboto_Mono/RobotoMono-Medium.ttf", 50 }), NULL, &tgt);
|
{ "Roboto_Mono/RobotoMono-Medium.ttf", 50 }), NULL, &tgt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//TODO display speedtest info
|
||||||
|
tgt.y += tgt.h + 25;
|
||||||
|
TTF_SizeText(board::getFont({ "Roboto_Mono/RobotoMono-Medium.ttf", 50 }),
|
||||||
|
speedtest_ping.c_str(), &tgt.w, &tgt.h);
|
||||||
|
SDL_RenderCopy(board::getRenderer(),
|
||||||
|
board::getString(speedtest_ping.c_str(),
|
||||||
|
{ "Roboto_Mono/RobotoMono-Medium.ttf", 50 }), NULL, &tgt);
|
||||||
|
|
||||||
|
tgt.y += tgt.h + 25;
|
||||||
|
TTF_SizeText(board::getFont({ "Roboto_Mono/RobotoMono-Medium.ttf", 50 }),
|
||||||
|
speedtest_up.c_str(), &tgt.w, &tgt.h);
|
||||||
|
SDL_RenderCopy(board::getRenderer(),
|
||||||
|
board::getString(speedtest_up.c_str(),
|
||||||
|
{ "Roboto_Mono/RobotoMono-Medium.ttf", 50 }), NULL, &tgt);
|
||||||
|
|
||||||
|
tgt.y += tgt.h + 25;
|
||||||
|
TTF_SizeText(board::getFont({ "Roboto_Mono/RobotoMono-Medium.ttf", 50 }),
|
||||||
|
speedtest_down.c_str(), &tgt.w, &tgt.h);
|
||||||
|
SDL_RenderCopy(board::getRenderer(),
|
||||||
|
board::getString(speedtest_down.c_str(),
|
||||||
|
{ "Roboto_Mono/RobotoMono-Medium.ttf", 50 }), NULL, &tgt);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
SDL_SetRenderTarget(board::getRenderer(), NULL);
|
SDL_SetRenderTarget(board::getRenderer(), NULL);
|
||||||
}
|
}
|
||||||
@ -148,8 +257,8 @@ void wifi::initTexture(){
|
|||||||
std::cerr << "WIFI INIT TEXTURE\n";
|
std::cerr << "WIFI INIT TEXTURE\n";
|
||||||
if(_texture == nullptr){
|
if(_texture == nullptr){
|
||||||
_texture = SDL_CreateTexture(board::getRenderer(),
|
_texture = SDL_CreateTexture(board::getRenderer(),
|
||||||
SDL_PIXELFORMAT_RGBA8888,
|
SDL_PIXELFORMAT_RGBA8888,
|
||||||
SDL_TEXTUREACCESS_TARGET,
|
SDL_TEXTUREACCESS_TARGET,
|
||||||
SCREEN_WIDTH, SCREEN_HEIGHT);
|
SCREEN_WIDTH, SCREEN_HEIGHT);
|
||||||
|
|
||||||
SDL_SetTextureBlendMode(_texture, SDL_BLENDMODE_BLEND);
|
SDL_SetTextureBlendMode(_texture, SDL_BLENDMODE_BLEND);
|
||||||
@ -158,7 +267,7 @@ void wifi::initTexture(){
|
|||||||
|
|
||||||
///////////////////////////////////////
|
///////////////////////////////////////
|
||||||
// Curl callback function
|
// Curl callback function
|
||||||
size_t dashboard::panel::wifi::curl_callback(void* contents, size_t size,
|
size_t dashboard::panel::wifi::curl_callback(void* contents, size_t size,
|
||||||
size_t nmemb, void* userp){
|
size_t nmemb, void* userp){
|
||||||
((std::string*)userp)->append((char*)contents, size * nmemb);
|
((std::string*)userp)->append((char*)contents, size * nmemb);
|
||||||
return size * nmemb;
|
return size * nmemb;
|
||||||
|
@ -13,8 +13,10 @@
|
|||||||
#include <SDL2/SDL_ttf.h>
|
#include <SDL2/SDL_ttf.h>
|
||||||
|
|
||||||
#include <curl/curl.h>
|
#include <curl/curl.h>
|
||||||
|
#include "../util/rapidjson/document.h"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
namespace dashboard::panel {
|
namespace dashboard::panel {
|
||||||
class wifi : public panel {
|
class wifi : public panel {
|
||||||
@ -29,6 +31,19 @@ namespace dashboard::panel {
|
|||||||
void update();
|
void update();
|
||||||
void update_texture();
|
void update_texture();
|
||||||
void initTexture();
|
void initTexture();
|
||||||
|
|
||||||
|
std::string public_ip;
|
||||||
|
bool wan_status;
|
||||||
|
std::string speedtest_up;
|
||||||
|
std::string speedtest_down;
|
||||||
|
std::string speedtest_ping;
|
||||||
|
|
||||||
|
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;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -16,11 +16,11 @@ namespace dashboard::panel {
|
|||||||
constexpr size_t WIFI_DEFAULT_TIME_ON_SCREEN = 15000;
|
constexpr size_t WIFI_DEFAULT_TIME_ON_SCREEN = 15000;
|
||||||
|
|
||||||
//How long should we wait between updates? in ms
|
//How long should we wait between updates? in ms
|
||||||
//Due to the nature of this panel, this value is ignored
|
//Default 60s
|
||||||
constexpr size_t WIFI_UPDATE_INTERVAL = 60000;
|
constexpr size_t WIFI_UPDATE_INTERVAL = 60000;
|
||||||
|
|
||||||
//Set to true to have your public IP be shown on the wifi page
|
//Set to true to have your public IP be shown on the wifi page
|
||||||
//Will make a curl request to WIFI_PUBLIC_IP_URL when the frame
|
//Will make a curl request to WIFI_PUBLIC_IP_URL when the frame
|
||||||
//is rendered. This this is a privacy concern disable this option
|
//is rendered. This this is a privacy concern disable this option
|
||||||
constexpr bool WIFI_SHOW_PUBLIC_IP = true;
|
constexpr bool WIFI_SHOW_PUBLIC_IP = true;
|
||||||
constexpr char WIFI_PUBLIC_IP_URL[] = "http://ipinfo.io/ip";
|
constexpr char WIFI_PUBLIC_IP_URL[] = "http://ipinfo.io/ip";
|
||||||
@ -31,4 +31,36 @@ namespace dashboard::panel {
|
|||||||
constexpr char WIFI_NETWORK_NAME[] = "MyNetwork";
|
constexpr char WIFI_NETWORK_NAME[] = "MyNetwork";
|
||||||
constexpr char WIFI_NETWORK_PASS[] = "MyPassword";
|
constexpr char WIFI_NETWORK_PASS[] = "MyPassword";
|
||||||
|
|
||||||
|
// Set to true if you have home assistant on your network
|
||||||
|
// If you do, you can do alot more with it, including showing number of
|
||||||
|
// clients, network speed, etc
|
||||||
|
constexpr bool WIFI_HOMEASSISTANT = true;
|
||||||
|
|
||||||
|
//API and URL for home assistant. If using the home assistant panel, this
|
||||||
|
//should be the same
|
||||||
|
constexpr char WIFI_HOMEASSISTANT_APIKEY[] = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiIxYTNhNDhhYTBlZDM0MjkyOTk5OWZhNGVjZGRjMGUwMCIsImlhdCI6MTY0MjE4NDU0MCwiZXhwIjoxOTU3NTQ0NTQwfQ.Zdy7-ZwX0HuwhmUGeLhF5XCluotsKmpDqmi5o-hQZCc";
|
||||||
|
constexpr char WIFI_HOMEASSISTANT_URL[] = "http://192.168.1.104:8123/api/states";
|
||||||
|
|
||||||
|
//Name of the external IP sensor entry in home assistant
|
||||||
|
//If your router integrates with it, then you should be able to find it in
|
||||||
|
//integrations
|
||||||
|
constexpr char WIFI_HOMEASSISTANT_ROUTER_EXTERNAL_IP[] = "sensor.r7000p_gateway_external_ip";
|
||||||
|
|
||||||
|
//Name of WAN status sensor in home assistant
|
||||||
|
constexpr char WIFI_HOMEASSISTANT_ROUTER_WAN_STATUS[] = "sensor.r7000p_gateway_wan_status";
|
||||||
|
|
||||||
|
//Enable this if you have the ookla speedtest module on home assistant
|
||||||
|
constexpr bool WIFI_HOMEASSISTANT_SPEEDTEST = true;
|
||||||
|
|
||||||
|
//Name of the entity id string used by the speedtest upload sensor in home
|
||||||
|
//assistant
|
||||||
|
constexpr char WIFI_HOMEASSISTANT_SPEEDTEST_UP[] = "sensor.speedtest_upload";
|
||||||
|
|
||||||
|
//Name of the entity id string used by the speedtest download sensor in home
|
||||||
|
//assistant
|
||||||
|
constexpr char WIFI_HOMEASSISTANT_SPEEDTEST_DOWN[] = "sensor.speedtest_download";
|
||||||
|
|
||||||
|
//Name of the entity id string used by the speedtest ping sensor in home
|
||||||
|
//assistant
|
||||||
|
constexpr char WIFI_HOMEASSISTANT_SPEEDTEST_PING[] = "sensor.speedtest_ping";
|
||||||
}
|
}
|
||||||
|
10
tests/getHA.sh
Executable file
10
tests/getHA.sh
Executable file
@ -0,0 +1,10 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
API_KEY=$(pass gluttony/homeassistant/API)
|
||||||
|
IP_ADDR="192.168.1.104"
|
||||||
|
|
||||||
|
curl -X GET \
|
||||||
|
-H "Authorization: Bearer $API_KEY" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-o out.json \
|
||||||
|
http://$IP_ADDR:8123/api/states
|
Loading…
Reference in New Issue
Block a user