mirror of https://github.com/cutefishos/core
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
413 lines
10 KiB
C++
413 lines
10 KiB
C++
#include "battery.h"
|
|
#include "power.h"
|
|
#include "primarybatteryadaptor.h"
|
|
|
|
#include <QDateTime>
|
|
#include <QDebug>
|
|
|
|
enum TimeConstants {
|
|
SecsInDay = 86400,
|
|
SecsInHour = 3600,
|
|
SecsInMinute = 60
|
|
};
|
|
|
|
// ref: https://upower.freedesktop.org/docs/Device.html
|
|
// kf5solid
|
|
|
|
Battery::Battery(UPowerDevice *device, QObject *parent)
|
|
: QObject(parent)
|
|
, m_device(device)
|
|
, m_settings(nullptr)
|
|
, m_lastChargedPercent(0)
|
|
, m_lastChargedSecs(0)
|
|
{
|
|
connect(device, SIGNAL(changed()), this, SLOT(slotChanged()));
|
|
|
|
updateCache();
|
|
init();
|
|
}
|
|
|
|
void Battery::updateCache()
|
|
{
|
|
m_chargeState = chargeState();
|
|
m_isPresent = isPresent();
|
|
m_chargePercent = chargePercent();
|
|
m_capacity = capacity();
|
|
m_isPowerSupply = isPowerSupply();
|
|
m_timeToEmpty = timeToEmpty();
|
|
m_timeToFull = timeToFull();
|
|
m_energy = energy();
|
|
m_energyFull = energyFull();
|
|
m_energyFullDesign = energyFullDesign();
|
|
m_energyRate = energyRate();
|
|
m_voltage = voltage();
|
|
m_temperature = temperature();
|
|
}
|
|
|
|
void Battery::init()
|
|
{
|
|
if (type() == Battery::PrimaryBattery) {
|
|
new PrimaryBatteryAdaptor(this);
|
|
QDBusConnection::sessionBus().registerObject(QStringLiteral("/PrimaryBattery"), this);
|
|
|
|
m_settings = new QSettings(QStringLiteral("cutefishos"), QStringLiteral("PrimaryBattery"));
|
|
m_lastChargedPercent = m_settings->value("LastChargedPercent", 0).toInt();
|
|
m_lastChargedSecs = m_settings->value("LastChargedSecs").toLongLong();
|
|
}
|
|
}
|
|
|
|
void Battery::refresh()
|
|
{
|
|
QDBusInterface iface(UP_DBUS_SERVICE, m_device->udi(),
|
|
UP_DBUS_INTERFACE_DEVICE, QDBusConnection::systemBus());
|
|
if (iface.isValid())
|
|
iface.call("Refresh");
|
|
}
|
|
|
|
bool Battery::isPresent() const
|
|
{
|
|
return m_device->prop("IsPresent").toBool();
|
|
}
|
|
|
|
Battery::BatteryType Battery::type() const
|
|
{
|
|
Battery::BatteryType result = Battery::UnknownBattery;
|
|
const uint t = m_device->prop("Type").toUInt();
|
|
|
|
switch (t) {
|
|
case UP_DEVICE_KIND_LINE_POWER: // TODO
|
|
break;
|
|
case UP_DEVICE_KIND_BATTERY:
|
|
result = Battery::PrimaryBattery;
|
|
break;
|
|
case UP_DEVICE_KIND_UPS:
|
|
result = Battery::UpsBattery;
|
|
break;
|
|
case UP_DEVICE_KIND_MONITOR:
|
|
result = Battery::MonitorBattery;
|
|
break;
|
|
case UP_DEVICE_KIND_MOUSE:
|
|
result = Battery::MouseBattery;
|
|
break;
|
|
case UP_DEVICE_KIND_KEYBOARD:
|
|
result = Battery::KeyboardBattery;
|
|
break;
|
|
case UP_DEVICE_KIND_PDA:
|
|
result = Battery::PdaBattery;
|
|
break;
|
|
case UP_DEVICE_KIND_PHONE:
|
|
result = Battery::PhoneBattery;
|
|
break;
|
|
case UP_DEVICE_KIND_GAMING_INPUT:
|
|
result = Battery::GamingInputBattery;
|
|
break;
|
|
case UP_DEVICE_KIND_UNKNOWN: {
|
|
// There is currently no "Bluetooth battery" type, so check if it comes from Bluez
|
|
if (m_device->prop("NativePath").toString().startsWith(QLatin1String("/org/bluez/"))) {
|
|
result = Battery::BluetoothBattery;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
int Battery::chargePercent() const
|
|
{
|
|
return qRound(m_device->prop("Percentage").toDouble());
|
|
}
|
|
|
|
int Battery::capacity() const
|
|
{
|
|
return m_device->prop("Capacity").toDouble();
|
|
}
|
|
|
|
bool Battery::isRechargeable() const
|
|
{
|
|
return m_device->prop("IsRechargeable").toBool();
|
|
}
|
|
|
|
bool Battery::isPowerSupply() const
|
|
{
|
|
return m_device->prop("PowerSupply").toBool();
|
|
}
|
|
|
|
Battery::ChargeState Battery::chargeState() const
|
|
{
|
|
Battery::ChargeState result = Battery::NoCharge;
|
|
const uint state = m_device->prop("State").toUInt();
|
|
switch (state) {
|
|
case 0:
|
|
result = Battery::NoCharge; // stable or unknown
|
|
break;
|
|
case 1:
|
|
result = Battery::Charging;
|
|
break;
|
|
case 2:
|
|
result = Battery::Discharging;
|
|
break;
|
|
case 3: // TODO "Empty"
|
|
break;
|
|
case 4:
|
|
result = Battery::FullyCharged;
|
|
break;
|
|
case 5: // TODO "Pending charge"
|
|
break;
|
|
case 6: // TODO "Pending discharge"
|
|
break;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
qlonglong Battery::timeToEmpty() const
|
|
{
|
|
return m_device->prop("TimeToEmpty").toLongLong();
|
|
}
|
|
|
|
qlonglong Battery::timeToFull() const
|
|
{
|
|
return m_device->prop("TimeToFull").toLongLong();
|
|
}
|
|
|
|
Battery::Technology Battery::technology() const
|
|
{
|
|
const uint tech = m_device->prop("Technology").toUInt();
|
|
switch (tech) {
|
|
case 1:
|
|
return Battery::LithiumIon;
|
|
case 2:
|
|
return Battery::LithiumPolymer;
|
|
case 3:
|
|
return Battery::LithiumIronPhosphate;
|
|
case 4:
|
|
return Battery::LeadAcid;
|
|
case 5:
|
|
return Battery::NickelCadmium;
|
|
case 6:
|
|
return Battery::NickelMetalHydride;
|
|
default:
|
|
return Battery::UnknownTechnology;
|
|
}
|
|
}
|
|
|
|
double Battery::energy() const
|
|
{
|
|
return m_device->prop("Energy").toDouble();
|
|
}
|
|
|
|
double Battery::energyFull() const
|
|
{
|
|
return m_device->prop("EnergyFull").toDouble();
|
|
}
|
|
|
|
double Battery::energyFullDesign() const
|
|
{
|
|
return m_device->prop("EnergyFullDesign").toDouble();
|
|
}
|
|
|
|
double Battery::energyRate() const
|
|
{
|
|
return m_device->prop("EnergyRate").toDouble();
|
|
}
|
|
|
|
double Battery::voltage() const
|
|
{
|
|
return m_device->prop("Voltage").toDouble();
|
|
}
|
|
|
|
double Battery::temperature() const
|
|
{
|
|
return m_device->prop("Temperature").toDouble();
|
|
}
|
|
|
|
bool Battery::isRecalled() const
|
|
{
|
|
return m_device->prop("RecallNotice").toBool();
|
|
}
|
|
|
|
QString Battery::recallVendor() const
|
|
{
|
|
return m_device->prop("RecallVendor").toString();
|
|
}
|
|
|
|
QString Battery::recallUrl() const
|
|
{
|
|
return m_device->prop("RecallUrl").toString();
|
|
}
|
|
|
|
QString Battery::serial() const
|
|
{
|
|
return m_device->prop("Serial").toString();
|
|
}
|
|
|
|
qlonglong Battery::remainingTime() const
|
|
{
|
|
if (chargeState() == Battery::Charging) {
|
|
return timeToFull();
|
|
} else if (chargeState() == Battery::Discharging) {
|
|
return timeToEmpty();
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
QString Battery::formatDuration(qlonglong seconds) const
|
|
{
|
|
QString result;
|
|
quint64 secs = seconds;
|
|
|
|
int days = secs / SecsInDay;
|
|
secs = secs % SecsInDay;
|
|
int hours = secs / SecsInHour;
|
|
secs = secs % SecsInHour;
|
|
int minutes = secs / SecsInMinute;
|
|
|
|
if (days > 0)
|
|
result.push_back(tr("%1d").arg(days));
|
|
|
|
if (hours > 0) {
|
|
if (days > 0)
|
|
result.push_back(" ");
|
|
|
|
result.push_back(tr("%1h").arg(hours));
|
|
}
|
|
|
|
if (minutes > 0) {
|
|
if (hours > 0)
|
|
result.push_back(" ");
|
|
|
|
result.push_back(tr("%1m").arg(minutes));
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
QString Battery::statusString() const
|
|
{
|
|
if (chargeState() == Battery::Charging) {
|
|
return tr("%1 until fully charged").arg(formatDuration(remainingTime()));
|
|
} else if (chargeState() == Battery::Discharging) {
|
|
return tr("%1 remaining").arg(formatDuration(remainingTime()));
|
|
} else if (chargeState() == Battery::FullyCharged) {
|
|
return tr("Fully charged.");
|
|
}
|
|
|
|
return QString();
|
|
}
|
|
|
|
int Battery::lastChargedPercent() const
|
|
{
|
|
return m_lastChargedPercent;
|
|
}
|
|
|
|
quint64 Battery::lastChargedSecs() const
|
|
{
|
|
return m_lastChargedSecs;
|
|
}
|
|
|
|
QString Battery::lastChargedTime() const
|
|
{
|
|
QDateTime now = QDateTime::currentDateTime();
|
|
QDateTime time = QDateTime::fromSecsSinceEpoch(m_lastChargedSecs);
|
|
qint64 minutes = qRound64(time.secsTo(now) / 60.0f);
|
|
|
|
if (minutes == 0)
|
|
return tr("now");
|
|
|
|
return tr("%1 ago").arg(formatDuration(time.secsTo(now)));
|
|
}
|
|
|
|
void Battery::slotChanged()
|
|
{
|
|
if (m_device) {
|
|
const bool old_isPresent = m_isPresent;
|
|
const int old_chargePercent = m_chargePercent;
|
|
const int old_capacity = m_capacity;
|
|
const bool old_isPowerSupply = m_isPowerSupply;
|
|
const Battery::ChargeState old_chargeState = m_chargeState;
|
|
const qlonglong old_timeToEmpty = m_timeToEmpty;
|
|
const qlonglong old_timeToFull = m_timeToFull;
|
|
const double old_energy = m_energy;
|
|
const double old_energyFull = m_energyFull;
|
|
const double old_energyFullDesign = m_energyFullDesign;
|
|
const double old_energyRate = m_energyRate;
|
|
const double old_voltage = m_voltage;
|
|
const double old_temperature = m_temperature;
|
|
|
|
updateCache();
|
|
|
|
if (old_isPresent != m_isPresent) {
|
|
emit presentStateChanged(m_isPresent);
|
|
}
|
|
|
|
if (old_chargePercent != m_chargePercent) {
|
|
emit chargePercentChanged(m_chargePercent);
|
|
}
|
|
|
|
if (old_capacity != m_capacity) {
|
|
emit capacityChanged(m_capacity);
|
|
}
|
|
|
|
if (old_isPowerSupply != m_isPowerSupply) {
|
|
emit powerSupplyStateChanged(m_isPowerSupply);
|
|
}
|
|
|
|
if (old_chargeState != m_chargeState) {
|
|
emit chargeStateChanged(m_chargeState);
|
|
}
|
|
|
|
// Save last charge percentage
|
|
if ((old_chargeState == Battery::Charging || old_chargeState == Battery::FullyCharged) &&
|
|
m_chargeState == Battery::Discharging) {
|
|
m_lastChargedPercent = m_chargePercent;
|
|
m_lastChargedSecs = QDateTime::currentSecsSinceEpoch();
|
|
|
|
if (m_settings) {
|
|
m_settings->setValue("LastChargedPercent", m_lastChargedPercent);
|
|
m_settings->setValue("LastChargedSecs", m_lastChargedSecs);
|
|
}
|
|
|
|
emit lastChargedPercentChanged();
|
|
emit lastChargedSecsChanged();
|
|
}
|
|
|
|
if (old_timeToEmpty != m_timeToEmpty) {
|
|
emit timeToEmptyChanged(m_timeToEmpty);
|
|
}
|
|
|
|
if (old_timeToFull != m_timeToFull) {
|
|
emit timeToFullChanged(m_timeToFull);
|
|
}
|
|
|
|
if (old_energy != m_energy) {
|
|
emit energyChanged(m_energy);
|
|
}
|
|
|
|
if (old_energyFull != m_energyFull) {
|
|
emit energyFullChanged(m_energyFull);
|
|
}
|
|
|
|
if (old_energyFullDesign != m_energyFullDesign) {
|
|
emit energyFullChanged(m_energyFullDesign);
|
|
}
|
|
|
|
if (old_energyRate != m_energyRate) {
|
|
emit energyRateChanged(m_energyRate);
|
|
}
|
|
|
|
if (old_voltage != m_voltage) {
|
|
emit voltageChanged(m_voltage);
|
|
}
|
|
|
|
if (old_temperature != m_temperature) {
|
|
emit temperatureChanged(m_temperature);
|
|
}
|
|
|
|
if (old_timeToFull != m_timeToFull || old_timeToEmpty != m_timeToEmpty) {
|
|
emit remainingTimeChanged(remainingTime());
|
|
}
|
|
}
|
|
}
|