Compare commits

..

10 Commits

Author SHA1 Message Date
Tyler Perkins
998f355460 Change type MBps to Mbps 2022-01-28 17:42:46 -05:00
Tyler Perkins
cbcba7d143 Add homeassistant network stats to wifi panel 2022-01-28 17:34:14 -05:00
Tyler Perkins
4e513a86d8 Fix trailing spaces 2022-01-28 17:33:24 -05:00
Tyler Perkins
fed9d23ed8 Add home assistant test script 2022-01-28 17:31:26 -05:00
Tyler Perkins
d857ae85cf Update README with goals 2022-01-28 16:42:52 -05:00
Tyler Perkins
1d8fa2600c Update internal tautulli api key 2022-01-18 13:51:43 -05:00
Tyler Perkins
9a2cf809ed Fix time in homeassistant.cpp to account for timezone 2022-01-17 15:13:05 -05:00
Tyler Perkins
9018d83868 Add home assistant bare bones panel 2022-01-17 15:03:34 -05:00
Tyler Perkins
05ae49976b Tweak plex panel code formatting 2022-01-17 15:03:13 -05:00
Tyler Perkins
5f06845b1c Add FAQ to DEVELOPMENT 2022-01-17 15:02:20 -05:00
17 changed files with 561 additions and 66 deletions

3
.gitignore vendored
View File

@ -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

View File

@ -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

View File

@ -16,6 +16,7 @@ Features/TODO
- 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

View File

@ -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
@ -50,6 +52,7 @@ 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]);

View File

@ -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[];

223
src/panel/homeassistant.cpp Normal file
View 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;
}

View 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"

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

View File

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

View File

@ -14,9 +14,9 @@ namespace dashboard::panel {
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;
} }

View File

@ -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,8 +67,87 @@ 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
}
} }
/////////////////////////////////////// ///////////////////////////////////////
@ -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);
} }

View File

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

View File

@ -16,7 +16,7 @@ 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
@ -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
View 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