File indexing completed on 2024-04-21 04:56:49
0001 /** 0002 * SPDX-FileCopyrightText: 2013 Albert Vaca <albertvaka@gmail.com> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0005 */ 0006 0007 #include "batteryplugin.h" 0008 0009 #include <KLocalizedString> 0010 #include <KPluginFactory> 0011 0012 #include <Solid/Battery> 0013 #include <Solid/Device> 0014 #include <Solid/Predicate> 0015 0016 #include <core/daemon.h> 0017 0018 #include "plugin_battery_debug.h" 0019 0020 K_PLUGIN_CLASS_WITH_JSON(BatteryPlugin, "kdeconnect_battery.json") 0021 0022 const auto batteryDevice = Solid::DeviceInterface::Type::Battery; 0023 const auto primary = Solid::Battery::BatteryType::PrimaryBattery; 0024 0025 BatteryPlugin::BatteryPlugin(QObject *parent, const QVariantList &args) 0026 : KdeConnectPlugin(parent, args) 0027 { 0028 QList<Solid::Device> batteries = Solid::Device::listFromQuery(Solid::Predicate(batteryDevice, QStringLiteral("type"), primary)); 0029 0030 if (batteries.isEmpty()) { 0031 qCWarning(KDECONNECT_PLUGIN_BATTERY) << "No Primary Battery detected on this system. This may be a bug."; 0032 QList<Solid::Device> allBatteries = Solid::Device::listFromType(batteryDevice); 0033 qCWarning(KDECONNECT_PLUGIN_BATTERY) << "Total quantity of batteries found: " << allBatteries.size(); 0034 return; 0035 } 0036 0037 // Ok, there's at least one. Let's assume it will remain attached (for most laptops 0038 // and desktops, this is a safe assumption). 0039 const Solid::Battery *chosen = batteries.first().as<Solid::Battery>(); 0040 0041 connect(chosen, &Solid::Battery::chargeStateChanged, this, &BatteryPlugin::slotChargeChanged); 0042 connect(chosen, &Solid::Battery::chargePercentChanged, this, &BatteryPlugin::slotChargeChanged); 0043 } 0044 0045 int BatteryPlugin::charge() const 0046 { 0047 return m_charge; 0048 } 0049 0050 bool BatteryPlugin::isCharging() const 0051 { 0052 return m_isCharging; 0053 } 0054 0055 void BatteryPlugin::connected() 0056 { 0057 // Explicitly send the current charge 0058 slotChargeChanged(); 0059 } 0060 0061 void BatteryPlugin::slotChargeChanged() 0062 { 0063 // Note: the NetworkPacket sent at the end of this method can reflect MULTIPLE batteries. 0064 // We average the total charge against the total number of batteries, which in practice 0065 // seems to work out ok. 0066 bool isAnyBatteryCharging = false; 0067 int batteryQuantity = 0; 0068 int cumulativeCharge = 0; 0069 0070 QList<Solid::Device> batteries = Solid::Device::listFromQuery(Solid::Predicate(batteryDevice, QStringLiteral("type"), primary)); 0071 0072 for (auto device : batteries) { 0073 const Solid::Battery *battery = device.as<Solid::Battery>(); 0074 0075 // Don't look at batteries that can be easily detached 0076 if (battery->isPowerSupply()) { 0077 batteryQuantity++; 0078 cumulativeCharge += battery->chargePercent(); 0079 if (battery->chargeState() == Solid::Battery::ChargeState::Charging) { 0080 isAnyBatteryCharging = true; 0081 } 0082 } 0083 } 0084 0085 if (batteryQuantity == 0) { 0086 qCWarning(KDECONNECT_PLUGIN_BATTERY) << "Primary Battery seems to have been removed. Suspending packets until it is reconnected."; 0087 return; 0088 } 0089 0090 // Load a new Battery object to represent the first device in the list 0091 Solid::Battery *chosen = batteries.first().as<Solid::Battery>(); 0092 0093 // Prepare an outgoing network packet 0094 NetworkPacket status(PACKET_TYPE_BATTERY, {{}}); 0095 status.set(QStringLiteral("isCharging"), isAnyBatteryCharging); 0096 const int charge = cumulativeCharge / batteryQuantity; 0097 status.set(QStringLiteral("currentCharge"), charge); 0098 // FIXME: In future, we should consider sending an array of battery objects 0099 status.set(QStringLiteral("batteryQuantity"), batteryQuantity); 0100 // We consider the primary battery to be low if it's below 15% 0101 if (charge <= 15 && chosen->chargeState() == Solid::Battery::ChargeState::Discharging) { 0102 status.set(QStringLiteral("thresholdEvent"), (int)ThresholdBatteryLow); 0103 } else { 0104 status.set(QStringLiteral("thresholdEvent"), (int)ThresholdNone); 0105 } 0106 sendPacket(status); 0107 } 0108 0109 void BatteryPlugin::receivePacket(const NetworkPacket &np) 0110 { 0111 m_isCharging = np.get<bool>(QStringLiteral("isCharging"), false); 0112 m_charge = np.get<int>(QStringLiteral("currentCharge"), -1); 0113 const int thresholdEvent = np.get<int>(QStringLiteral("thresholdEvent"), (int)ThresholdNone); 0114 0115 Q_EMIT refreshed(m_isCharging, m_charge); 0116 0117 if (thresholdEvent == ThresholdBatteryLow && !m_isCharging) { 0118 Daemon::instance()->sendSimpleNotification(QStringLiteral("batteryLow"), 0119 i18nc("device name: low battery", "%1: Low Battery", device()->name()), 0120 i18n("Battery at %1%", m_charge), 0121 QStringLiteral("battery-040")); 0122 } 0123 } 0124 0125 QString BatteryPlugin::dbusPath() const 0126 { 0127 return QLatin1String("/modules/kdeconnect/devices/%1/battery").arg(device()->id()); 0128 } 0129 0130 #include "batteryplugin.moc" 0131 #include "moc_batteryplugin.cpp"