Всем привет!
Предыстория (можете пропустить)
Долго думал, писать или не писать статью про мою библиотеку, которой активно пользуюсь и тестирую уже который месяц.
Но недавно обнаружил, что «очередное решение несуществующей проблемы» в виде моего личного Android порта Blender 5.3.0 Alpha, ушло в массы и начало жить своей жизнью, а люди на Reddit выкладывают видосы с тем, как они работают на своих Android планшетах. Причём, мой оригинальный пост собрал еле‑еле 3 стрелочки вверх на Reddit, а пост с видосами да и форк моего репозитория получили дикие отклики по меркам их сабреддитов.
Потому решил, таки рассказать, про самописные вещи, которые лежат в опенсорсе и которыми я активно пользуюсь.
Вступление
Гуглил я как‑то опенсорс C++ библиотеку для мониторинга, температуры и нагрузки компонентов ПК. И не нагуглил. Вот такие вот дела. Есть HWiNFO, платно и закрыто. Есть OpenHardwareMonitor — написан C# и библиотека мертва. Есть форк предыдущей библиотеки — LibreHardwareMonitor — живее всех живых, но C#, да ещё и по дефолту требует 10.NET.
Зачем нужен C++, когда можно подцепить DLL из C# напрямую? Ну вот не хочу я таскать.NET определенной версии с собой из бандла в бандл. AOT компиляция вообще не поможет, тут как раз то самое использование специфических вещей, которые AOT не компилит. Finita la comedia! А ещё есть один косяк у последней библиотеки: мака нет в списке поддержки от слова совсем.
“Одно кольцо, чтоб править всеми” Windows, Linux, MacOS — x64, arm64. Вот тут я и решил сесть и написать её. В очередной раз. Тем более что меня уволили и времени теперь вагон, можно потрогать все свои пэт проджекты. Тем более что есть референс в виде LibreHardwareMonitor.
Правда то, что он есть, хорошо и плохо одновременно. Нельзя сделать, как у них, потому что «лицензия, детка»! Мне их лицензия не нравится. Надо избавлятся, делать надо не так.
Встречайте HardwareMonitorCpp (hardware_monitor_cpp)!
Пытался я получить температуру процессора без повышения привилегий. Гайки, никак. One Ring0 to rule them all! Ну, на винде и макоси, по крайней мере, Ring0 обязателен, Linux может и без этого.
Остальное работает и без sudo. Что такое остальное? Общая информация о железе: как железка называется, сколько у неё частота, память занятая/свободная, текущая температура и текущая нагрузка. Полноценный мониторинг, одним словом. Понятно, что у процессора нет занятой свободной памяти, а у SSD нет текущей частоты, но есть количество активного времени и IO Bound.
Чем классная библиотека?
Ну, во‑первых, к ней сразу идёт Python сервер, которые все эти данные выдает в сеть! Так же есть консольная приложуха, которая выдаёт эти данные визуально в консоль (со своими собственными настройками, котрые сохраняются между запусками). Писать 100 500 утилит не стал. Я пользуюсь только консольной приложухой на винде и маке. Очень нравится, легким движением руки переключаюсь между нагрузкой и температурой (кнопка «t»), а таймскейл на колонку меняю с 1 секунды на 5 минут (кнопки «‑» и «=»). Очень удобно, особенно, чтобы прикинуть визуально, сколько ещё проекту собираться, и сколько он собирался в прошлый раз. И сколько он выжрал оперативы, например.
А ещё на Windows и MacOS наконец‑то есть внятный график и размер файла подкачки. Я сколько не смотрел в TaskManager и ActivityMonitor, так надо найти 2 числа и дальше математикой заниматься. Не круто! Тут сразу видно, что к чему.
Все написано на C++. Потому что я плюсовик и я могу! Консольное приложение в ходе разработки раздулось с 7 мб оперативы до 30 мб на винде. Да и только потому, что я решил больше снапшотов системы хранить в истории отображения.
Из плюшек библиотеки: можно запросить по всему оборудованию только нагрузку или только температуру.
Из минусов: для Windows нужно отдельно ставить PawnIO для цифер процессора, но это нормально. LibreHardwareMontior тоже драйвер таскает и запускатет от имени администратора, для того же самого. Судьба такая. HWiNFO тоже, вот, не просто так просит поднять привелегии.
Что я делать не стал: мониторить температуру материнки и обороты вентилятора. Мне самой температуры железок хватает, чтобы понять, что к чему. А писать код вслепую для 100 500 вендоров не хочется, хоть и есть куда подглядеть.
Консольное приложение и Python сервер
Вместе с самой библиотекой в комплекте идёт консольное приложение и отдельно сервер на Python, который выдаёт эту информацию в сеть.


Несмотря на то, что они могут не покрыть ваши нужды, приложение и сервер — хорошая точка старта. Потом с помощью молотка и напильника можно получить то, что бы вам хотелось. Ну и да, сборка питоновского сервера сразу оборачивает биндинги библиотеки в питоновское расширение, так что можно будет использовать бинарь и в других местах.
Билдится всё очень просто. Всё, что нужно — установленные ninja и cmake, и чтобы они были доступны в Path. Дальше достаточно запустить один из python скриптов сборки. Их три:
python build_lib.py
python build_console.py
python build_server.py
Сборки самодостаточные. После подтягивания саб модулей ничего дополнительно кроме запуска скрипта сборки делать не нужно. В README.md всё подробно описано.
Если впадлу билдить, уже есть готовые сборки релизов (но там не всё).
Примеры использования кода
Вывод температуры ядер:
#include <iostream> #include <HardwareMonitorCpp/HardwareMonitor.hpp> int main() { // Инициализация мониторинга HardwareMonitor::HardwareManager monitor; monitor.Update(); // Получаем список всех доступных процессоров auto cpus = monitor.GetCpuHardware(); for (const auto& cpu : cpus) { std::cout << "Процессор: " << cpu->GetName() << "\n"; // Выводим только температуру ядер for (const auto& sensor : cpu->GetSensors()) { if (sensor->GetSensorType() == HardwareMonitor::SensorType::Temperature) { std::cout << " " << sensor->GetName() << ": " << sensor->GetValue().value_or(0) << " °C\n"; } } } return 0; }
Монитор загрузки системных ресурсов:
#include <iostream> #include <thread> #include <chrono> #include <HardwareMonitorCpp/HardwareMonitor.hpp> void PrintSystemStatus(HardwareMonitor::HardwareManager& monitor) { monitor.Update(); // 1. Загрузка CPU for (const auto& cpu : monitor.GetCpuHardware()) { for (const auto& sensor : cpu->GetSensors()) { if (sensor->GetSensorType() == HardwareMonitor::SensorType::Load && sensor->GetName() == "CPU Total") { std::cout << "[CPU] Загрузка: " << sensor->GetValue().value_or(0) << "%\n"; } } } // 2. Использование GPU и температуры for (const auto& gpu : monitor.GetGpuHardware()) { std::cout << "[GPU] " << gpu->GetName() << ":\n"; for (const auto& sensor : gpu->GetSensors()) { if (sensor->GetSensorType() == HardwareMonitor::SensorType::Temperature) { std::cout << " - Температура: " << sensor->GetValue().value_or(0) << " °C\n"; } if (sensor->GetSensorType() == HardwareMonitor::SensorType::Load) { std::cout << " - Загрузка ядра: " << sensor->GetValue().value_or(0) << "%\n"; } } } } int main() { HardwareMonitor::HardwareManager monitor; // Цикл мониторинга раз в секунду for (int i = 0; i < 5; ++i) { std::cout << "=== Обновление данных (" << i + 1 << ") ===\n"; PrintSystemStatus(monitor); std::this_thread::sleep_for(std::chrono::seconds(1)); } return 0; }
Безопасный опрос датчиков
Иногда датчики у той или иной железки могут быть недоступны. Например у одного SSD: есть мониторинг температуры, у дргого нет.
#include <iostream> #include <HardwareMonitorCpp/HardwareMonitor.hpp> // Вспомогательная функция для безопасного получения значения void PrintSensorValue(const std::shared_ptr<HardwareMonitor::ISensor>& sensor) { std::cout << "Датчик: " << sensor->GetName() << " | "; if (auto value = sensor->GetValue(); value.has_value()) { std::cout << "Значение: " << *value; } else { std::cout << "Данные недоступны"; } std::cout << "\n"; } int main() { HardwareMonitor::HardwareManager monitor; monitor.Update(); // Получаем оперативную память for (const auto& ram : monitor.GetRamHardware()) { std::cout << "Модуль RAM: " << ram->GetName() << "\n"; for (const auto& sensor : ram->GetSensors()) { PrintSensorValue(sensor); } } return 0; }
Спасибо за внимание!
Библиотеку можно скачать здесь https://github.com/simfeo/HardwareMonitorCpp или
git clone https://github.com/simfeo/HardwareMonitorCpp.git cd HardwareMonitorCpp git submodule update --init --recursive
Как и в прошлой статье про другую мою библиотеку, готов к конструктивной критике, и делать апдейты. После отзывов библиотека, кстати, немного подросла, но серьезно улушилась в синтаксисе использования. Если кому интересно, есть статья на медиум, но пока что на английском, так как большая половина критики прилетела с Reddit.

