[OpenDocString] kdeconnect-kde (cpp)
batteryplugin.cpp
BatteryPlugin::BatteryPlugin(QObject *parent, const QVariantList &args)
    : KdeConnectPlugin(parent, args)
{
}
Constructs a battery plugin object and assigns its data to its parent object. The args parameter is a list of arguments that will be passed to the plugin at the constructor.
int BatteryPlugin::charge() const
{
    return m_charge;
}
Returns the charge count in the internal list.
bool BatteryPlugin::isCharging() const
{
    return m_isCharging;
}
This implements checking if the plugin is charging.
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();
}
This sends a network packet to request battery information from the remote device, and determines if there are any batteries that can be connected. It first gets the primary battery of the system, and if it doesn't have any, it gets the batteries list from the query, and if there are any, it gets the first battery in the list, and sets the signal slotChargeChanged to the corresponding signal. Finally, it sends the current charge percent change signal to the appropriate signal.
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);
}
This sends a status network packet to determine if the primary battery is charging. It first retrieves the batteries of the given type, and sums the cumulative charge against the total number of batteries, which can be easily detached, which means that the primary battery is charging. Then it checks if the battery is power supply, which means that the primary battery is not charging. If the battery is not power supply, it is ignored. If there are no batteries in the list, it sends a status network packet to set the isCharging value false. If the battery is not a power supply, the number of batteries are added to the list, and a warning message is printed to the console.
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;
}
This retrieves information about the network package and emits a refresh signal. It takes the isCharging value from the network object, and the current charge value, and returns true.
QString BatteryPlugin::dbusPath() const
{
    return QStringLiteral("/modules/kdeconnect/devices/") + device()->id() + QStringLiteral("/battery");
}
Returns the dbus path as a QString.