Add home assistant bare bones panel
This commit is contained in:
parent
05ae49976b
commit
9018d83868
@ -10,10 +10,12 @@
|
||||
// A list of all panels to be displayed, in order
|
||||
dashboard::panel::panel* PANELS[] = {
|
||||
//new dashboard::panel::sample_panel(),
|
||||
new dashboard::panel::homeassistant(),
|
||||
new dashboard::panel::plex(),
|
||||
new dashboard::panel::weather(),
|
||||
new dashboard::panel::wifi(),
|
||||
};
|
||||
|
||||
size_t PANELS_LENGTH = sizeof(PANELS)/sizeof(PANELS[0]);
|
||||
|
||||
// OVERLAY
|
||||
@ -49,7 +51,8 @@ const char* IMAGE_LOCATIONS[] = {
|
||||
|
||||
//plex
|
||||
"plex_background.jpg",
|
||||
|
||||
|
||||
//homeassistant
|
||||
};
|
||||
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 } },
|
||||
{ "Wireless", { "Roboto_Mono/RobotoMono-Medium.ttf", 50 } },
|
||||
{ "Plex", { "Roboto_Mono/RobotoMono-Medium.ttf", 50} },
|
||||
{ "Homeassistant", { "Roboto_Mono/RobotoMono-Medium.ttf", 50} },
|
||||
//sample panel
|
||||
//{ "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} },
|
||||
{ "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]);
|
||||
|
@ -79,6 +79,7 @@ constexpr int IMG_FLAGS = 0
|
||||
#include "panel/def_overlay.hpp"
|
||||
#include "panel/wifi.hpp"
|
||||
#include "panel/plex.hpp"
|
||||
#include "panel/homeassistant.hpp"
|
||||
//uncomment this to use the sample panel
|
||||
//#include "panel/sample_panel.hpp"
|
||||
extern dashboard::panel::panel* PANELS[];
|
||||
|
225
src/panel/homeassistant.cpp
Normal file
225
src/panel/homeassistant.cpp
Normal file
@ -0,0 +1,225 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// 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);
|
||||
|
||||
std::cerr << json_string << "\n";
|
||||
|
||||
//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);
|
||||
}
|
||||
|
||||
///////////////////////////////////////
|
||||
// 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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user