177 lines
5.6 KiB
C++
177 lines
5.6 KiB
C++
#include <sys/statvfs.h>
|
|
|
|
#include <array>
|
|
#include <chrono>
|
|
#include <csignal>
|
|
#include <cstdint>
|
|
#include <cstdlib>
|
|
#include <iostream>
|
|
#include <print>
|
|
#include <sstream>
|
|
#include <stop_token>
|
|
#include <string>
|
|
#include <thread>
|
|
//
|
|
#include <LCDDisplay.hpp>
|
|
#include <cpu.hpp>
|
|
#include <gpu.hpp>
|
|
#include <hass.hpp>
|
|
#include <sys.hpp>
|
|
#include <utils.hpp>
|
|
|
|
#define LCD_PORT "/dev/serial/by-id/usb-Raspberry_Pi_Pico_E6616407E37AA12F-if00" // tis a symlink, can also be just /dev/ttyACM0
|
|
#define LCD_INTERVAL_MS 1000
|
|
#define LCD_CONTRAST 215
|
|
#define FILL_CHAR ' '
|
|
|
|
std::chrono::milliseconds interval(LCD_INTERVAL_MS);
|
|
std::stop_source sigint;
|
|
|
|
struct mem_usage_t {
|
|
uint64_t free = 0;
|
|
uint64_t used = 0;
|
|
uint64_t total = 0;
|
|
};
|
|
|
|
struct sensors_t {
|
|
std::array<std::string, 2> td;
|
|
std::string loadavg;
|
|
mem_usage_t ram;
|
|
mem_usage_t home;
|
|
gpu_t gpu;
|
|
cpu_t cpu;
|
|
float hass_state = 0;
|
|
};
|
|
|
|
/* DISPLAY FUNCS */
|
|
|
|
// pads given string to length
|
|
std::string pad(std::string s, uint8_t len, bool ljust = false) {
|
|
if (len > s.size())
|
|
s.insert(ljust ? s.end() : s.begin(), len - s.size(), FILL_CHAR);
|
|
return s;
|
|
}
|
|
|
|
// fills n spaces
|
|
std::string fill(uint8_t n) {
|
|
return std::string(n, FILL_CHAR);
|
|
}
|
|
|
|
/* GETTERS */
|
|
|
|
mem_usage_t getRam() {
|
|
mem_usage_t mem;
|
|
std::ifstream proc_meminfo("/proc/meminfo");
|
|
|
|
if (proc_meminfo.good()) {
|
|
std::string content((std::istreambuf_iterator<char>(proc_meminfo)), std::istreambuf_iterator<char>());
|
|
mem.free = get_val("MemAvailable:", content);
|
|
mem.total = get_val("MemTotal:", content);
|
|
mem.used = mem.total - mem.free;
|
|
}
|
|
proc_meminfo.close();
|
|
return mem;
|
|
}
|
|
|
|
mem_usage_t getDisk(std::string mount) {
|
|
mem_usage_t disk;
|
|
struct statvfs diskData;
|
|
statvfs(mount.c_str(), &diskData);
|
|
disk.free = diskData.f_bfree * diskData.f_frsize;
|
|
disk.used = (diskData.f_blocks - diskData.f_bfree) * diskData.f_frsize;
|
|
disk.total = diskData.f_blocks * diskData.f_frsize;
|
|
return disk;
|
|
}
|
|
|
|
void sighandler(int s) {
|
|
std::println("[Signal] got SIGINT, exiting...");
|
|
sigint.request_stop();
|
|
}
|
|
|
|
void hass_thread(sensors_t *s, std::stop_token st) {
|
|
std::println("[Thread] Starting hass_thread, pid {}", gettid());
|
|
hass_connect();
|
|
while (!st.stop_requested()) {
|
|
hass_poll();
|
|
s->hass_state = hass_get();
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
|
}
|
|
hass_disconnect();
|
|
}
|
|
|
|
void sensors_thread(sensors_t *s, std::stop_token st) {
|
|
std::println("[Thread] Starting sensors_thread, pid {}", gettid());
|
|
/* find hwmon paths from pci addresses */
|
|
cpu_hwmon_t cpu_hwmon = detectCpuHwmon("0000:00:18.3");
|
|
std::string gpu_hwmon = detectGpuHwmon("0000:08:00.0");
|
|
|
|
while (!st.stop_requested()) {
|
|
auto start = std::chrono::steady_clock::now();
|
|
s->td = getTimeDate();
|
|
s->loadavg = getAvgs();
|
|
s->ram = getRam();
|
|
s->home = getDisk("/home/drath");
|
|
s->cpu = getCpu(cpu_hwmon);
|
|
s->gpu = getGpu(gpu_hwmon);
|
|
|
|
// std::print("[Sensors] took {} microseconds \r", std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::steady_clock::now() - start).count());
|
|
// std::cout << std::flush;
|
|
std::this_thread::sleep_until(start + interval);
|
|
}
|
|
}
|
|
|
|
void display_thread(sensors_t *s, std::stop_token st) {
|
|
std::println("[Thread] Starting display_thread, pid {}", gettid());
|
|
LCDDisplay lcd(LCD_PORT);
|
|
lcd.setCustomChar(0, {16, 6, 9, 8, 8, 9, 6, 0}); // celcius
|
|
|
|
std::println("[Chrono] Running in daemon mode, {} ms interval", LCD_INTERVAL_MS);
|
|
lcd.setContrast(LCD_CONTRAST);
|
|
lcd.setBacklight(true);
|
|
lcd.clear();
|
|
|
|
while (!st.stop_requested()) {
|
|
auto start = std::chrono::steady_clock::now();
|
|
std::array<std::string, 4> lines;
|
|
|
|
auto gpu_temps = (s->gpu.hotspot_temp) ? "/" + std::to_string(s->gpu.hotspot_temp) : "";
|
|
gpu_temps += (s->gpu.mem_temp) ? "/" + std::to_string(s->gpu.mem_temp) : "";
|
|
|
|
lcd.writeBuf(0, 0, pad(s->td[1], 11, true) + " " + s->td[0] + lcd.bar(1, s->gpu.core_usage / 100.0) + pad(s->loadavg, 17));
|
|
|
|
lcd.writeBuf(1, 0, pad(std::to_string(s->cpu.tctl) + "/" + std::to_string(s->cpu.tccd1) + lcd.cc[0], 8, true));
|
|
lcd.writeBuf(1, 11, pad(pBytes(s->ram.used, true) + "B", 7, true));
|
|
lcd.writeBuf(1, 22, pad(pBytes(s->gpu.vram_used) + "B", 7));
|
|
lcd.writeBuf(1, 29, pad(std::to_string(s->gpu.edge_temp) + gpu_temps + lcd.cc[0], 11));
|
|
|
|
lcd.writeBuf(2, 0, pad(pNum(s->cpu.ptotal, 1) + "W", 8, true));
|
|
lcd.writeBuf(2, 10, pad(pNum(s->hass_state) + "W", 4));
|
|
lcd.writeBuf(2, 15, pad("h:" + pBytes(s->home.free), 8));
|
|
|
|
// lcd.writeBuf(2, 25, pad(s->gpu.fan_speed + "R", 5));
|
|
// std::println("{}", s->gpu.fan_speed);
|
|
lcd.writeBuf(2, 31, pad(std::to_string(s->gpu.power_avg) + "/" + std::to_string(s->gpu.power_cap) + "W", 9));
|
|
|
|
lcd.writeBuf(3, 0, pad(pNum(s->cpu.vcore, 3) + "V", 7, true));
|
|
lcd.writeBuf(3, 7, std::to_string(s->cpu.avg_freq) + "MHz");
|
|
lcd.writeBuf(3, 21, pad(std::to_string(s->gpu.core_clock) + "/" + std::to_string(s->gpu.mem_clock) + "MHz ", 13));
|
|
lcd.writeBuf(3, 34, pad(pNum(s->gpu.vcore, 3) + "V", 5));
|
|
|
|
lcd.flushBuffer();
|
|
|
|
std::this_thread::sleep_until(start + interval);
|
|
}
|
|
}
|
|
|
|
int main(int argc, char *argv[]) {
|
|
signal(SIGINT, sighandler);
|
|
|
|
sensors_t sensors;
|
|
|
|
std::jthread producer(sensors_thread, &sensors, sigint.get_token());
|
|
std::jthread hass(hass_thread, &sensors, sigint.get_token());
|
|
|
|
display_thread(&sensors, sigint.get_token());
|
|
return 0;
|
|
}
|