File indexing completed on 2024-05-12 17:00:17

0001 /*
0002     SPDX-FileCopyrightText: 2020 David Redondo <kde@david-redondo.de>
0003 
0004     SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0005 */
0006 
0007 #include "power.h"
0008 
0009 #include <KLocalizedString>
0010 #include <KPluginFactory>
0011 #include <Solid/Device>
0012 #include <Solid/DeviceNotifier>
0013 #include <Solid/Battery>
0014 
0015 #include <systemstats/AggregateSensor.h>
0016 #include <systemstats/SensorContainer.h>
0017 #include <systemstats/SensorObject.h>
0018 #include <systemstats/SensorProperty.h>
0019 
0020 K_PLUGIN_CLASS_WITH_JSON(PowerPlugin, "metadata.json")
0021 
0022 QString idHelper(const Solid::Device battery)
0023 {
0024     const QString serial = battery.as<Solid::Battery>()->serial();
0025     if (!serial.isEmpty()) {
0026         return serial;
0027     }
0028     return battery.udi().mid(battery.udi().lastIndexOf(QLatin1Char('/')) + 1);
0029 }
0030 
0031 class Battery : public KSysGuard::SensorObject {
0032 public:
0033     Battery(const Solid::Device &device, const QString &name, KSysGuard::SensorContainer *parent);
0034 };
0035 
0036 Battery::Battery(const Solid::Device &device, const QString &name, KSysGuard::SensorContainer *parent)
0037     : SensorObject(idHelper(device), name, parent)
0038 {
0039     auto n = new KSysGuard::SensorProperty("name", i18nc("@title", "Name"), name, this);
0040     n->setVariantType(QVariant::String);
0041 
0042     const auto * const battery = device.as<Solid::Battery>();
0043 
0044     auto designCapacity = new KSysGuard::SensorProperty("design", i18nc("@title", "Design Capacity"), battery->energyFullDesign(), this);
0045     designCapacity->setShortName(i18nc("@title", "Design Capacity"));
0046     designCapacity->setPrefix(name);
0047     designCapacity->setDescription(i18n("Amount of energy that the Battery was designed to hold"));
0048     designCapacity->setUnit(KSysGuard::UnitWattHour);
0049     designCapacity->setVariantType(QVariant::Double);;
0050     designCapacity->setMin(battery->energyFullDesign());
0051     designCapacity->setMax(battery->energyFullDesign());
0052 
0053     auto currentCapacity = new KSysGuard::SensorProperty("capacity", i18nc("@title", "Current Capacity"), battery->energyFull(), this);
0054     currentCapacity->setShortName(i18nc("@title", "Current Capacity"));
0055     currentCapacity->setPrefix(name);
0056     currentCapacity->setDescription(i18n("Amount of energy that the battery can currently hold"));
0057     currentCapacity->setUnit(KSysGuard::UnitWattHour);
0058     currentCapacity->setVariantType(QVariant::Double);
0059     currentCapacity->setMax(designCapacity);
0060     connect(battery, &Solid::Battery::energyFullChanged, currentCapacity, &KSysGuard::SensorProperty::setValue);
0061 
0062     auto health = new KSysGuard::SensorProperty("health", i18nc("@title", "Health"), battery->capacity(), this);
0063     health->setShortName(i18nc("@title", "Health"));
0064     health->setPrefix(name);
0065     health->setDescription(i18n("Percentage of the design capacity that the battery can hold"));
0066     health->setUnit(KSysGuard::UnitPercent);
0067     health->setVariantType(QVariant::Int);
0068     health->setMax(100);
0069     connect(battery, &Solid::Battery::capacityChanged, health, &KSysGuard::SensorProperty::setValue);
0070 
0071     auto charge = new KSysGuard::SensorProperty("charge", i18nc("@title", "Charge"), battery->energy(), this);
0072     charge->setShortName(i18nc("@title", "Current Capacity"));
0073     charge->setPrefix(name);
0074     charge->setDescription(i18n("Amount of energy that the battery is currently holding"));
0075     charge->setUnit(KSysGuard::UnitWattHour);
0076     charge->setVariantType(QVariant::Double);
0077     charge->setMax(currentCapacity);
0078     connect(battery, &Solid::Battery::energyChanged, charge, &KSysGuard::SensorProperty::setValue);
0079 
0080     auto chargePercent = new KSysGuard::SensorProperty("chargePercentage", i18nc("@title", "Charge Percentage"), battery->chargePercent(), this);
0081     chargePercent->setShortName(i18nc("@title", "Charge Percentage"));
0082     chargePercent->setPrefix(name);
0083     chargePercent->setDescription(i18n("Percentage of the current capacity that the battery is currently holding"));
0084     chargePercent->setUnit(KSysGuard::UnitPercent);
0085     chargePercent->setVariantType(QVariant::Int);
0086     chargePercent->setMax(100);
0087     connect(battery, &Solid::Battery::chargePercentChanged, chargePercent, &KSysGuard::SensorProperty::setValue);
0088 
0089     // Solid reports negative of charging and positive for discharging
0090     auto chargeRate = new KSysGuard::SensorProperty("chargeRate", i18nc("@title", "Charging Rate"), 0, this);
0091     chargeRate->setShortName(i18nc("@title", "Charging  Rate"));
0092     chargeRate->setPrefix(name);
0093     chargeRate->setDescription(i18n("Power that the battery is being charged with (positive) or discharged (negative)"));
0094     chargeRate->setUnit(KSysGuard::UnitWatt);
0095     chargeRate->setVariantType(QVariant::Double);
0096     chargeRate->setValue(-battery->energyRate());
0097     connect(battery, &Solid::Battery::energyRateChanged, chargeRate, [chargeRate] (double rate) {
0098         chargeRate->setValue(-rate);
0099     });
0100 
0101 }
0102 
0103 PowerPlugin::PowerPlugin(QObject *parent, const QVariantList &args)
0104     : SensorPlugin(parent, args)
0105 {
0106     m_container = new KSysGuard::SensorContainer("power", i18nc("@title", "Power"), this);
0107     const auto batteries = Solid::Device::listFromType(Solid::DeviceInterface::Battery);
0108 
0109     for (const auto &device : batteries) {
0110         auto battery = new Battery(device, device.displayName(), m_container);
0111         m_batteriesByUdi.insert(device.udi(), battery);
0112     }
0113 
0114     connect(Solid::DeviceNotifier::instance(), &Solid::DeviceNotifier::deviceAdded, this, [this] (const QString &udi) {
0115         const Solid::Device device(udi);
0116         if (device.isDeviceInterface(Solid::DeviceInterface::Battery)) {
0117             auto battery = new Battery(device, device.displayName(), m_container);
0118             m_batteriesByUdi.insert(udi, battery);
0119         }
0120     });
0121     connect(Solid::DeviceNotifier::instance(), &Solid::DeviceNotifier::deviceRemoved, this, [this] (const QString &udi) {
0122         if (m_batteriesByUdi.contains(udi)) {
0123             m_container->removeObject(m_batteriesByUdi[udi]);
0124             m_batteriesByUdi.remove(udi);
0125         }
0126     });
0127 }
0128 
0129 #include "power.moc"