File indexing completed on 2024-05-12 05:36:18

0001 /*
0002  * SPDX-FileCopyrightText: 2015 David Edmundson <david@davidedmundson.co.uk>
0003  *
0004  * SPDX-License-Identifier: LGPL-2.1-or-later
0005  *
0006  */
0007 
0008 #include "statisticsprovider.h"
0009 
0010 #include <QDBusArgument>
0011 #include <QDBusConnection>
0012 #include <QDBusInterface>
0013 #include <QDBusMessage>
0014 #include <QDBusMetaType> // qDBusRegisterMetaType
0015 #include <QDBusPendingReply>
0016 #include <QDebug>
0017 
0018 const QDBusArgument &operator<<(QDBusArgument &argument, const HistoryReply &data)
0019 {
0020     argument.beginStructure();
0021     argument << data.time << data.value << data.charging;
0022     argument.endStructure();
0023     return argument;
0024 }
0025 
0026 const QDBusArgument &operator>>(const QDBusArgument &arg, HistoryReply &attrs)
0027 {
0028     arg.beginStructure();
0029     arg >> attrs.time >> attrs.value >> attrs.charging;
0030     arg.endStructure();
0031     return arg;
0032 }
0033 
0034 StatisticsProvider::StatisticsProvider(QObject *parent)
0035     : QObject(parent)
0036 {
0037     m_type = StatisticsProvider::ChargeType;
0038     m_duration = 120;
0039 
0040     qDBusRegisterMetaType<HistoryReply>();
0041     qDBusRegisterMetaType<QList<HistoryReply>>();
0042 }
0043 
0044 void StatisticsProvider::setDevice(const QString &device)
0045 {
0046     if (device == m_device) {
0047         return;
0048     }
0049 
0050     m_device = device;
0051     Q_EMIT deviceChanged();
0052 
0053     load();
0054 }
0055 
0056 void StatisticsProvider::setDuration(uint duration)
0057 {
0058     if (duration == m_duration) {
0059         return;
0060     }
0061 
0062     m_duration = duration;
0063     Q_EMIT durationChanged();
0064 
0065     load();
0066 }
0067 
0068 void StatisticsProvider::setType(StatisticsProvider::HistoryType type)
0069 {
0070     if (m_type == type) {
0071         return;
0072     }
0073 
0074     m_type = type;
0075     Q_EMIT typeChanged();
0076 
0077     load();
0078 }
0079 
0080 void StatisticsProvider::classBegin()
0081 {
0082 }
0083 
0084 void StatisticsProvider::componentComplete()
0085 {
0086     m_isComplete = true;
0087     load();
0088 }
0089 
0090 QVariantList StatisticsProvider::asPoints() const
0091 {
0092     QVariantList points;
0093     points.reserve(m_values.count());
0094     foreach (const HistoryReply &h, m_values) {
0095         points.append(QPointF(h.time, h.value));
0096     }
0097 
0098     if (!points.isEmpty()) {
0099         points.takeLast();
0100     }
0101 
0102     return points;
0103 }
0104 
0105 int StatisticsProvider::count() const
0106 {
0107     return m_values.count();
0108 }
0109 
0110 int StatisticsProvider::firstDataPointTime() const
0111 {
0112     if (m_values.isEmpty()) {
0113         return 0;
0114     }
0115 
0116     return m_values.first().time;
0117 }
0118 
0119 int StatisticsProvider::lastDataPointTime() const
0120 {
0121     if (m_values.isEmpty()) {
0122         return 0;
0123     }
0124 
0125     return m_values.last().time;
0126 }
0127 
0128 int StatisticsProvider::largestValue() const
0129 {
0130     if (m_values.isEmpty()) {
0131         return 0;
0132     }
0133 
0134     int max = 0; // TODO std::max or something?
0135     for (auto it = m_values.constBegin(), end = m_values.constEnd(); it != end; ++it) {
0136         if ((*it).value > max) {
0137             max = (*it).value;
0138         }
0139     }
0140     return max;
0141 }
0142 
0143 void StatisticsProvider::refresh()
0144 {
0145     load();
0146 }
0147 
0148 void StatisticsProvider::load()
0149 {
0150     if (!m_isComplete || m_device.isEmpty()) {
0151         return;
0152     }
0153 
0154     auto msg = QDBusMessage::createMethodCall(QStringLiteral("org.freedesktop.UPower"),
0155                                               m_device,
0156                                               QStringLiteral("org.freedesktop.UPower.Device"),
0157                                               QStringLiteral("GetHistory"));
0158     if (m_type == RateType) {
0159         msg << QLatin1String("rate");
0160     } else { // m_type must = ChargeType
0161         msg << QLatin1String("charge");
0162     }
0163 
0164     uint resolution = 100;
0165     msg << m_duration << resolution;
0166 
0167     QDBusPendingReply<QList<HistoryReply>> reply = QDBusConnection::systemBus().asyncCall(msg);
0168 
0169     auto *watcher = new QDBusPendingCallWatcher(reply, this);
0170     QObject::connect(watcher, &QDBusPendingCallWatcher::finished, this, [this](QDBusPendingCallWatcher *watcher) {
0171         QDBusPendingReply<QList<HistoryReply>> reply = *watcher;
0172         watcher->deleteLater();
0173         m_values.clear();
0174 
0175         if (reply.isError()) {
0176             qWarning() << "Failed to get device history from UPower" << reply.error().message();
0177             return;
0178         }
0179 
0180         foreach (const HistoryReply &r, reply.value()) {
0181             if (r.value > 0) { // we get back some values which contain no value, possibly to indicate if charging changes, ignore them
0182                 m_values.prepend(r);
0183             }
0184         }
0185 
0186         Q_EMIT dataChanged();
0187     });
0188 }