1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
|
/*
SPDX-FileCopyrightText: 2020 David Redondo <kde@david-redondo.de>
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/
#include "power.h"
#include <KLocalizedString>
#include <KPluginFactory>
#include <Solid/Device>
#include <Solid/DeviceNotifier>
#include <Solid/Battery>
#include <systemstats/AggregateSensor.h>
#include <systemstats/SensorContainer.h>
#include <systemstats/SensorObject.h>
#include <systemstats/SensorProperty.h>
K_PLUGIN_CLASS_WITH_JSON(PowerPlugin, "metadata.json")
QString idHelper(const Solid::Device battery)
{
const QString serial = battery.as<Solid::Battery>()->serial();
if (!serial.isEmpty()) {
return serial;
}
return battery.udi().mid(battery.udi().lastIndexOf(QLatin1Char('/')) + 1);
}
class Battery : public KSysGuard::SensorObject {
public:
Battery(const Solid::Device &device, const QString &name, KSysGuard::SensorContainer *parent);
};
Battery::Battery(const Solid::Device &device, const QString &name, KSysGuard::SensorContainer *parent)
: SensorObject(idHelper(device), name, parent)
{
auto n = new KSysGuard::SensorProperty("name", i18nc("@title", "Name"), name, this);
n->setVariantType(QVariant::String);
const auto * const battery = device.as<Solid::Battery>();
auto designCapacity = new KSysGuard::SensorProperty("design", i18nc("@title", "Design Capacity"), battery->energyFullDesign(), this);
designCapacity->setShortName(i18nc("@title", "Design Capacity"));
designCapacity->setPrefix(name);
designCapacity->setDescription(i18n("Amount of energy that the Battery was designed to hold"));
designCapacity->setUnit(KSysGuard::UnitWattHour);
designCapacity->setVariantType(QVariant::Double);;
designCapacity->setMin(battery->energyFullDesign());
designCapacity->setMax(battery->energyFullDesign());
auto currentCapacity = new KSysGuard::SensorProperty("capacity", i18nc("@title", "Current Capacity"), battery->energyFull(), this);
currentCapacity->setShortName(i18nc("@title", "Current Capacity"));
currentCapacity->setPrefix(name);
currentCapacity->setDescription(i18n("Amount of energy that the battery can currently hold"));
currentCapacity->setUnit(KSysGuard::UnitWattHour);
currentCapacity->setVariantType(QVariant::Double);
currentCapacity->setMax(designCapacity);
connect(battery, &Solid::Battery::energyFullChanged, currentCapacity, &KSysGuard::SensorProperty::setValue);
auto health = new KSysGuard::SensorProperty("health", i18nc("@title", "Health"), battery->capacity(), this);
health->setShortName(i18nc("@title", "Health"));
health->setPrefix(name);
health->setDescription(i18n("Percentage of the design capacity that the battery can hold"));
health->setUnit(KSysGuard::UnitPercent);
health->setVariantType(QVariant::Int);
health->setMax(100);
connect(battery, &Solid::Battery::capacityChanged, health, &KSysGuard::SensorProperty::setValue);
auto charge = new KSysGuard::SensorProperty("charge", i18nc("@title", "Charge"), battery->energy(), this);
charge->setShortName(i18nc("@title", "Current Capacity"));
charge->setPrefix(name);
charge->setDescription(i18n("Amount of energy that the battery is currently holding"));
charge->setUnit(KSysGuard::UnitWattHour);
charge->setVariantType(QVariant::Double);
charge->setMax(currentCapacity);
connect(battery, &Solid::Battery::energyChanged, charge, &KSysGuard::SensorProperty::setValue);
auto chargePercent = new KSysGuard::SensorProperty("chargePercentage", i18nc("@title", "Charge Percentage"), battery->chargePercent(), this);
chargePercent->setShortName(i18nc("@title", "Charge Percentage"));
chargePercent->setPrefix(name);
chargePercent->setDescription(i18n("Percentage of the current capacity that the battery is currently holding"));
chargePercent->setUnit(KSysGuard::UnitPercent);
chargePercent->setVariantType(QVariant::Int);
chargePercent->setMax(100);
connect(battery, &Solid::Battery::chargePercentChanged, chargePercent, &KSysGuard::SensorProperty::setValue);
// Solid reports negative of charging and positive for discharging
auto chargeRate = new KSysGuard::SensorProperty("chargeRate", i18nc("@title", "Charging Rate"), 0, this);
chargeRate->setShortName(i18nc("@title", "Charging Rate"));
chargeRate->setPrefix(name);
chargeRate->setDescription(i18n("Power that the battery is being charged with (positive) or discharged (negative)"));
chargeRate->setUnit(KSysGuard::UnitWatt);
chargeRate->setVariantType(QVariant::Double);
chargeRate->setValue(-battery->energyRate());
connect(battery, &Solid::Battery::energyRateChanged, chargeRate, [battery, chargeRate] (double rate) {
// According to the documentation, energyRate should be positive if discharging
// and negative if charging. However, on some systems this turns out to be
// incorrect and we get positive both when charging and discharging. So ensure
// we have the right sign here by checking state.
if (battery->chargeState() == Solid::Battery::Charging) {
chargeRate->setValue(std::abs(rate));
} else if (battery->chargeState() == Solid::Battery::Discharging) {
chargeRate->setValue(-std::abs(rate));
} else {
chargeRate->setValue(rate);
}
});
}
PowerPlugin::PowerPlugin(QObject *parent, const QVariantList &args)
: SensorPlugin(parent, args)
{
m_container = new KSysGuard::SensorContainer("power", i18nc("@title", "Power"), this);
const auto batteries = Solid::Device::listFromType(Solid::DeviceInterface::Battery);
for (const auto &device : batteries) {
auto battery = new Battery(device, device.displayName(), m_container);
m_batteriesByUdi.insert(device.udi(), battery);
}
connect(Solid::DeviceNotifier::instance(), &Solid::DeviceNotifier::deviceAdded, this, [this] (const QString &udi) {
const Solid::Device device(udi);
if (device.isDeviceInterface(Solid::DeviceInterface::Battery)) {
auto battery = new Battery(device, device.displayName(), m_container);
m_batteriesByUdi.insert(udi, battery);
}
});
connect(Solid::DeviceNotifier::instance(), &Solid::DeviceNotifier::deviceRemoved, this, [this] (const QString &udi) {
if (m_batteriesByUdi.contains(udi)) {
m_container->removeObject(m_batteriesByUdi[udi]);
m_batteriesByUdi.remove(udi);
}
});
}
#include "power.moc"
#include "moc_power.cpp"
|