BatteryPlugin::BatteryPlugin(QObject *parent, const QVariantList &args)
: KdeConnectPlugin(parent, args)
{
}
int BatteryPlugin::charge() const
{
return m_charge;
}
bool BatteryPlugin::isCharging() const
{
return m_isCharging;
}
void BatteryPlugin::connected()
{
// We've just connected. Request battery information from the remote device...
NetworkPacket np(PACKET_TYPE_BATTERY_REQUEST, {{QStringLiteral("request"), true}});
sendPacket(np);
// ...and then figure out whether we have any batteries
const auto batteryDevice = Solid::DeviceInterface::Type::Battery;
const auto primary = Solid::Battery::BatteryType::PrimaryBattery;
QList batteries = Solid::Device::listFromQuery(Solid::Predicate(batteryDevice, QStringLiteral("type"), primary));
if (batteries.isEmpty()) {
qCWarning(KDECONNECT_PLUGIN_BATTERY) << "No Primary Battery detected on this system. This may be a bug.";
QList allBatteries = Solid::Device::listFromType(batteryDevice);
qCWarning(KDECONNECT_PLUGIN_BATTERY) << "Total quantity of batteries found: " << allBatteries.size();
return;
}
// Ok, there's at least one. Let's assume it will remain attached (for most laptops
// and desktops, this is a safe assumption).
const Solid::Battery *chosen = batteries.first().as();
connect(chosen, &Solid::Battery::chargeStateChanged, this, &BatteryPlugin::slotChargeChanged);
connect(chosen, &Solid::Battery::chargePercentChanged, this, &BatteryPlugin::slotChargeChanged);
// Explicitly send the current charge
slotChargeChanged();
}
void BatteryPlugin::slotChargeChanged()
{
// Note: the NetworkPacket sent at the end of this method can reflect MULTIPLE batteries.
// We average the total charge against the total number of batteries, which in practice
// seems to work out ok.
bool isAnyBatteryCharging = false;
int batteryQuantity = 0;
int cumulativeCharge = 0;
const auto batteryDevice = Solid::DeviceInterface::Type::Battery;
const auto primary = Solid::Battery::BatteryType::PrimaryBattery;
QList batteries = Solid::Device::listFromQuery(Solid::Predicate(batteryDevice, QStringLiteral("type"), primary));
for (auto device : batteries) {
const Solid::Battery *battery = device.as();
// Don't look at batteries that can be easily detached
if (battery->isPowerSupply()) {
batteryQuantity++;
cumulativeCharge += battery->chargePercent();
if (battery->chargeState() == Solid::Battery::ChargeState::Charging) {
isAnyBatteryCharging = true;
}
}
}
if (batteryQuantity == 0) {
qCWarning(KDECONNECT_PLUGIN_BATTERY) << "Primary Battery seems to have been removed. Suspending packets until it is reconnected.";
return;
}
// Load a new Battery object to represent the first device in the list
Solid::Battery *chosen = batteries.first().as();
// Prepare an outgoing network packet
NetworkPacket status(PACKET_TYPE_BATTERY, {{}});
status.set(QStringLiteral("isCharging"), isAnyBatteryCharging);
const int charge = cumulativeCharge / batteryQuantity;
status.set(QStringLiteral("currentCharge"), charge);
// FIXME: In future, we should consider sending an array of battery objects
status.set(QStringLiteral("batteryQuantity"), batteryQuantity);
// We consider the primary battery to be low if it's below 15%
if (charge <= 15 && chosen->chargeState() == Solid::Battery::ChargeState::Discharging) {
status.set(QStringLiteral("thresholdEvent"), (int)ThresholdBatteryLow);
} else {
status.set(QStringLiteral("thresholdEvent"), (int)ThresholdNone);
}
sendPacket(status);
}
bool BatteryPlugin::receivePacket(const NetworkPacket &np)
{
m_isCharging = np.get(QStringLiteral("isCharging"), false);
m_charge = np.get(QStringLiteral("currentCharge"), -1);
const int thresholdEvent = np.get(QStringLiteral("thresholdEvent"), (int)ThresholdNone);
Q_EMIT refreshed(m_isCharging, m_charge);
if (thresholdEvent == ThresholdBatteryLow && !m_isCharging) {
Daemon::instance()->sendSimpleNotification(QStringLiteral("batteryLow"),
i18nc("device name: low battery", "%1: Low Battery", device()->name()),
i18n("Battery at %1%", m_charge),
QStringLiteral("battery-040"));
}
return true;
}
QString BatteryPlugin::dbusPath() const
{
return QStringLiteral("/modules/kdeconnect/devices/") + device()->id() + QStringLiteral("/battery");
}