Evgenii Legotckoi
Evgenii Legotckoi01 квітня 2017 р. 12:16

Qt Linux - Урок 003. Перевірка рівня заряду батареї ноутбука за допомогою libacpi

Зайшла на форумі розмова про перевірку рівня заряду батареї ноутбука під Linux за допомогою бібліотеки Qt. За фактом Qt не надає на даний момент такого класу, який давав би можливість перевіряти заряд батареї.

Спробуємо створити додаток, який забиратиме хоч якісь дані, і який виглядатиме таким чином:


libacpi

Сама бібліотека написана на C і має такі, що цікавлять функції та структури даних:

  • global_t - глобальна структура даних, яка містить у собі кількість вентиляторів, батарей та теплових зон, а також структуру з адаптером живлення.
  • init_acpi_batt(global_t *globals) - ініціалізація даних про батареї
  • init_acpi_acadapt(global_t *globals) - ініціалізація даних про адаптер
  • init_acpi_fan(global_t *globals) - ініціалізація даних про вентилятори
  • init_acpi_thermal(global_t *globals) - ініціалізація даних про теплові зони
  • read_acpi_batt(int num) - зчитування даних про батареї
  • read_acpi_zone(int num, global_t *globals) - зчитування даних про теплові зони
  • read_acpi_fan(int num) - зчитування даних про вентилятори
  • battery_t - структура даних про батарею
  • fans_t - структура даних про вентилятори
  • thermal_t - структура даних про теплову зону
  • battery_t batteries [MAX_ITEMS] - масив батарей, в нього зберігаються дані при виклику read_acpi_batt
  • thermal_t thermals [MAX_ITEMS] - масив теплових зон, в нього зберігаються дані при виклику read_acpi_zone
  • fan_t fans [MAX_ITEMS] - масив вентиляторів, у нього зберігаються дані при викликі read_acpi_fan

Використання бібліотеки

Щоб використовувати бібліотеку у проекті на Qt, необхідно:

  1. Встановити бібліотеку з репозиторію:
sudo apt-get install libacpi-dev
  1. Підключити бібліотеку в pro-файлі проекту:
LIBS += -lacpi
  1. Підключити заголовковий файл бібліотеки у файлі вихідних кодів, де отримуватиме дані про заряд батареї:
#ifdef __cplusplus
extern "C" {
#endif

#include <libacpi.h>

#ifdef __cplusplus
}
#endif

Головне вікно програми

Головне вікно є класом Widget, який зроблений з використанням ui файлу і інтерфейс якого зроблений через графічний дизайнер. У ньому є ScrollArea, в якій розміщено об'єкт вертикального розміщення елементів, віджетів, які будуть створюватися динамічно, залежно від того, що змогла знайти бібліотека. Також є кнопка для запуску зчитування даних бібліотекою.

віджет.h

У заголовному файлі оголошено вектор з віджетами для батарей, вентиляторів і теплових зон. Також оголошено покажчик на віджет із адаптером живлення. Усі віджети є кастомними класами. Трохи далі буде як приклад наведено код одного з віджетів.

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>

#include "batterywidget.h"
#include "adapterwidget.h"
#include "fanwidget.h"
#include "thermalwidget.h"

namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = 0);
    ~Widget();

private slots:
    void on_pushButton_clicked();

private:
    Ui::Widget *ui;
    QVector<BatteryWidget*> m_butteryWidgetList;    // Вектор виджетов с батареями
    QVector<FanWidget*> m_fanWidgetList;            // Вектор виджетов с вентиляторами
    QVector<ThermalWidget*> m_thermalWidgetList;    // Вектор виджетов с тепловыми зонами
    AdapterWidget* m_adapterWidget;                 // Виджет для адаптера питания всегда один
};

#endif // WIDGET_H

widget.cpp

Оскільки бібліотека написана на C, їй властивий процедурний стиль виконання коду. А також є одна маленька хитрість. Справа в тому, що в бібліотеці є кілька глобальних змінних, які записуються дані. Це масиви з вентиляторами, тепловими зонами та батареями.

Тобто, коли ви викликаєте функцію read_acpi_batt(1) , то записуєте структуру даних battery_t в осередок масиву batteries[1].

Тоді як для створення глобальної структури, що містить дані про кількість всіх вище перерахованих структур, необхідно виділяти пам'ять.

#include "widget.h"
#include "ui_widget.h"

#ifdef __cplusplus
extern "C" {
#endif

#include <libacpi.h>

#ifdef __cplusplus
}
#endif

#include <QFileDialog>

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget),
    m_adapterWidget(nullptr)
{
    ui->setupUi(this);
}

Widget::~Widget()
{
    delete ui;
}

void Widget::on_pushButton_clicked()
{
    // Выделяем память под глобальную структуру данных бибилотеки
    global_t *global = static_cast<global_t*>(malloc(sizeof(global_t)));

    // Инициализируем структуру для
    init_acpi_batt(global);     // батареи
    init_acpi_acadapt(global);  // адаптера питания
    init_acpi_fan(global);      // вентиляторов
    init_acpi_thermal(global);  // тепловых зон

    // Battery
    battery_t *binfo;

    // Если нашлись батареи, то считываем в цикле данные и добавляем виджеты
    for(int i=0; i < global->batt_count; i++)
    {
        read_acpi_batt(i);      // считываем данные
        // которые считываются в специальный массив batteries - он есть в самой библиотеке
        binfo = &batteries[i];

        BatteryWidget* butteryWidget;
        // Создаём виджет
        if (m_butteryWidgetList.count() <= i)
        {
            butteryWidget = new BatteryWidget(this);
            butteryWidget->setTitle(QString(binfo->name));
            m_butteryWidgetList.append(butteryWidget);
            ui->verticalLayout->addWidget(butteryWidget);
        }
        else
        {
            // Или забираем его из списка виджетов
            butteryWidget = m_butteryWidgetList.at(i);
        }

        // Устанавливаем
        butteryWidget->setPercentage(binfo->percentage);        // Процент заряда
        butteryWidget->setChargeTime(binfo->charge_time);       // Время до полного заряда
        butteryWidget->setRemainingTime(binfo->remaining_time); // Время до полного разряда

        // Определяем статус заряда
        switch (binfo->charge_state)
        {
        case C_CHARGE:
            butteryWidget->setChargeState("Charging");
            break;
        case C_DISCHARGE:
            butteryWidget->setChargeState("Discharging");
        case C_CHARGED:
            butteryWidget->setChargeState("Charged");
        case C_NOINFO:
            butteryWidget->setChargeState("No info");
        default:
            butteryWidget->setChargeState("Error");
            break;
        }
    }

    // Adapter
    // Настройка виджета для адптера питания
    adapter_t *ac = &global->adapt;

    if (!m_adapterWidget)
    {
        m_adapterWidget = new AdapterWidget(this);
        ui->verticalLayout->addWidget(m_adapterWidget);
    }

    // Здесь проверяем только, подключён или нет
    switch (ac->ac_state)
    {
    case P_AC:
        m_adapterWidget->setStatus("Runs on AC");
        break;
    case P_BATT:
        m_adapterWidget->setStatus("Runs on battery");
    default:
        m_adapterWidget->setStatus("Error");
        break;
    }

    // Fan
    fan_t *finfo;

    // Если нашлись вентиляторы, то считываем в цикле данные и добавляем виджеты
    for(int i=0; i < global->fan_count; i++)
    {
        read_acpi_fan(i);   // считываем данные
        // которые считываются в специальный массив fans - он есть в самой библиотеке
        finfo = &fans[i];
        FanWidget* fanWidget;

        // Создаём виджет
        if (m_fanWidgetList.count() <= i)
        {
            fanWidget = new FanWidget(this);
            fanWidget->setTitle(QString(finfo->name));
            m_fanWidgetList.append(fanWidget);
            ui->verticalLayout->addWidget(fanWidget);
        }
        else
        {
            // Или забираем его из списка виджетов
            fanWidget = m_fanWidgetList.at(i);
        }

        // Устанавливаем статус, включён или нет
        switch (finfo->fan_state)
        {
        case F_ON:
            fanWidget->setStatus("ON");
            break;
        case F_OFF:
            fanWidget->setStatus("OFF");
        default:
            fanWidget->setStatus("Error");
            break;
        }
    }

    // Thermal
    thermal_t *tinfo;

    // Если нашлись тепловые зоны, то считываем в цикле данные и добавляем виджеты
    for(int i=0; i < global->fan_count; i++)
    {
        read_acpi_zone(i, global);  // считываем данные
        // которые считываются в специальный массив thermals - он есть в самой библиотеке
        tinfo = &thermals[i];
        ThermalWidget* thermalWidget;

        // Создаём виджет
        if (m_thermalWidgetList.count() <= i)
        {
            thermalWidget = new ThermalWidget(this);
            thermalWidget->setTitle(QString(tinfo->name));
            m_thermalWidgetList.append(thermalWidget);
            ui->verticalLayout->addWidget(thermalWidget);
        }
        else
        {
            // Или забираем его из списка виджетов
            thermalWidget = m_thermalWidgetList.at(i);
        }

        thermalWidget->setTemperature(tinfo->temperature);  // Устанавливаем температуру
        thermalWidget->setFrequency(tinfo->frequency);      // и частоту
    }

    free(global);
}

Віджети

У програмі є віджети для всіх вище перерахованих структур. Вони служать лише для відображення інформації та динамічного додавання. Наведу як приклад віджет, який відображає інформацію про батарею.

batterywidget.h

#ifndef BATTERYWIDGET_H
#define BATTERYWIDGET_H

#include <QWidget>

namespace Ui {
class BatteryWidget;
}

class BatteryWidget : public QWidget
{
    Q_OBJECT

public:
    explicit BatteryWidget(QWidget *parent = 0);
    ~BatteryWidget();

    void setTitle(QString title);               // Название батареи (как определено в ОС Linux)
    void setPercentage(int percentage);         // Процент заряда
    void setChargeTime(int chargeTime);         // Время до полного заряда в минутах
    void setRemainingTime(int remainingTime);   // Время до полного разряда в минутах
    void setChargeState(QString chargeState);   // Состояние

private:
    Ui::BatteryWidget *ui;
};

#endif // BATTERYWIDGET_H

batterywidget.cpp

#include "batterywidget.h"
#include "ui_batterywidget.h"

BatteryWidget::BatteryWidget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::BatteryWidget)
{
    ui->setupUi(this);
}

BatteryWidget::~BatteryWidget()
{
    delete ui;
}

void BatteryWidget::setTitle(QString title)
{
    ui->label_title->setText(title);
}

void BatteryWidget::setPercentage(int percentage)
{
    ui->label_percentage->setText(QString::number(percentage));
}

void BatteryWidget::setChargeTime(int chargeTime)
{
    ui->label_charge_time->setText(QString("%1:%2").arg(chargeTime / 60).arg(chargeTime % 60));
}

void BatteryWidget::setRemainingTime(int remainingTime)
{
    ui->label_remaining_time->setText(QString("%1:%2").arg(remainingTime / 60).arg(remainingTime % 60));
}

void BatteryWidget::setChargeState(QString chargeState)
{
    ui->label_charge_state->setText(chargeState);
}

Результат роботи бібліотеки

Результат роботи бібліотеки я назвав би задовільним, хоча вона і визначає відсотки заряду батареї, а також час для повного заряду батареї. Але час до розряду вона не визначила. А також не знайшла жодних вентиляторів та теплових зон. Вважаю, що на моїй моделі ноутбука ці дані просто недоступні. Також траплялися періодичні падіння програми при спробі доступу до деяких параметрів структур.

Скріншот, який наведено на початку статті, відображає ті дані, які бібліотека змогла знайти в моєму ноутбуці. Там звичайно, наведені не всі дані, якщо подивіться заголовковий файл бібліотеки, то виявите, що структури надають багатший вибір параметрів. Але для демонстрації запуску бібліотеки цього вважаю за достатнє.

Спробуйте запустити проект у себе і по можливості відпишіться, якщо у вас в ноутбуці дана бібліотека знайде теплові зони та вентилятори.

Проект заявки

Рекомендуємо хостинг TIMEWEB
Рекомендуємо хостинг TIMEWEB
Стабільний хостинг, на якому розміщується соціальна мережа EVILEG. Для проектів на Django радимо VDS хостинг.

Вам це подобається? Поділіться в соціальних мережах!

Коментарі

Only authorized users can post comments.
Please, Log in or Sign up
OI
  • Ora Iro
  • 24 грудня 2024 р. 17:38

C++ - Тест 001. Первая программа и типы данных

  • Результат:40бали,
  • Рейтинг балів-8
AD

C++ - Тест 004. Указатели, Массивы и Циклы

  • Результат:50бали,
  • Рейтинг балів-4
m
  • molni99
  • 26 жовтня 2024 р. 11:37

C++ - Тест 004. Указатели, Массивы и Циклы

  • Результат:80бали,
  • Рейтинг балів4
Останні коментарі
ИМ
Игорь Максимов22 листопада 2024 р. 22:51
Django - Підручник 017. Налаштуйте сторінку входу до Django Добрый вечер Евгений! Я сделал себе авторизацию аналогичную вашей, все работает, кроме возврата к предидущей странице. Редеректит всегда на главную, хотя в логах сервера вижу запросы на правильн…
Evgenii Legotckoi
Evgenii Legotckoi01 листопада 2024 р. 00:37
Django - Урок 064. Як написати розширення для Python Markdown Добрый день. Да, можно. Либо через такие же плагины, либо с постобработкой через python библиотеку Beautiful Soup
A
ALO1ZE19 жовтня 2024 р. 18:19
Читалка файлів fb3 на Qt Creator Подскажите как это запустить? Я не шарю в программировании и кодинге. Скачал и установаил Qt, но куча ошибок выдается и не запустить. А очень надо fb3 переконвертировать в html
ИМ
Игорь Максимов05 жовтня 2024 р. 17:51
Django - Урок 064. Як написати розширення для Python Markdown Приветствую Евгений! У меня вопрос. Можно ли вставлять свои классы в разметку редактора markdown? Допустим имея стандартную разметку: <ul> <li></li> <li></l…
d
dblas505 липня 2024 р. 21:02
QML - Урок 016. База даних SQLite та робота з нею в QML Qt Здравствуйте, возникает такая проблема (я новичок): ApplicationWindow неизвестный элемент. (М300) для TextField и Button аналогично. Могу предположить, что из-за более новой верси…
Тепер обговоріть на форумі
Donald Randolph
Donald Randolph30 грудня 2024 р. 13:59
Personal Injury lawyer Santa Monica As an experienced Santa Monica personal injury lawyer, Donald C. Randolph has recovered over $100 Million in verdicts and settlements for our clients. In severe injury cases, this compensation i…
Nirvana Yoga School
Nirvana Yoga School30 грудня 2024 р. 16:13
OAuth2.0 через VK, получение email Nirvana Yoga School is one of the most trusted and reputed traditional Rishikesh yoga courses , India certified by Yoga Alliance, USA. We aim to spread traditional yoga teachings so t…
s
sripark30 грудня 2024 р. 15:47
Mobile app development company in Chennai A Mobile app development company in Chennai focuses on creating personalized mobile applications to meet various business requirements. These companies offer a full range of services,…
a
amit8830 грудня 2024 р. 15:45
Excel in Exams with PSLE Maths Tuition Singapore Preparing for the PSLE can be challenging, but the right guidance makes all the difference. PSLE Maths tuition Singapore offers personalized coaching to help students master key concepts, improv…
a
awinash6230 грудня 2024 р. 15:23
Unlock Your Potential with the Certified Public Accountant Credential" Becoming a Certified Public Accountant (CPA) is a career milestone that opens doors to unparalleled opportunities in the world of accounting and finance. This globally recognized qualification s…

Слідкуйте за нами в соціальних мережах