diff --git a/sources/awesome-widget/plugin/awdataenginemapper.cpp b/sources/awesome-widget/plugin/awdataenginemapper.cpp index afcf602..581d0f0 100644 --- a/sources/awesome-widget/plugin/awdataenginemapper.cpp +++ b/sources/awesome-widget/plugin/awdataenginemapper.cpp @@ -106,7 +106,9 @@ QStringList AWDataEngineMapper::registerSource(const QString &_source, QString key = _source; key.remove("battery/"); m_map[_source] = key; - m_formatter[key] = AWKeysAggregator::FormatterType::IntegerThree; + m_formatter[key] = _source.contains("rate") + ? AWKeysAggregator::FormatterType::Float + : AWKeysAggregator::FormatterType::IntegerThree; } else if (_source == "cpu/system/TotalLoad") { // cpu m_map[_source] = "cpu"; diff --git a/sources/awesome-widget/plugin/awkeyoperations.cpp b/sources/awesome-widget/plugin/awkeyoperations.cpp index 7f992da..7f6cb1a 100644 --- a/sources/awesome-widget/plugin/awkeyoperations.cpp +++ b/sources/awesome-widget/plugin/awkeyoperations.cpp @@ -136,8 +136,13 @@ QStringList AWKeyOperations::dictKeys() const = QDir("/sys/class/power_supply") .entryList(QStringList({"BAT*"}), QDir::Dirs | QDir::NoDotAndDotDot, QDir::Name); - for (int i = 0; i < allBatteryDevices.count(); i++) + for (int i = 0; i < allBatteryDevices.count(); i++) { allKeys.append(QString("bat%1").arg(i)); + allKeys.append(QString("batleft%1").arg(i)); + allKeys.append(QString("batnow%1").arg(i)); + allKeys.append(QString("batrate%1").arg(i)); + allKeys.append(QString("battotal%1").arg(i)); + } // package manager for (auto &item : m_extUpgrade->activeItems()) allKeys.append(item->tag("pkgcount")); diff --git a/sources/extsysmonsources/batterysource.cpp b/sources/extsysmonsources/batterysource.cpp index b658e61..810ce9c 100644 --- a/sources/extsysmonsources/batterysource.cpp +++ b/sources/extsysmonsources/batterysource.cpp @@ -20,6 +20,8 @@ #include +#include + #include "awdebug.h" @@ -31,7 +33,6 @@ BatterySource::BatterySource(QObject *_parent, const QStringList &_args) m_acpiPath = _args.at(0); m_sources = getSources(); - m_timestamp = QDateTime::currentDateTimeUtc(); } @@ -50,12 +51,14 @@ QStringList BatterySource::getSources() sources.append("battery/batnow"); sources.append("battery/batrate"); sources.append("battery/battotal"); + m_batteriesCount = QDir(m_acpiPath) .entryList(QStringList({"BAT*"}), QDir::Dirs | QDir::NoDotAndDotDot, QDir::Name) .count(); qCInfo(LOG_ESS) << "Init batteries count as" << m_batteriesCount; + for (int i = 0; i < m_batteriesCount; i++) { sources.append(QString("battery/bat%1").arg(i)); sources.append(QString("battery/batleft%1").arg(i)); @@ -159,9 +162,6 @@ QVariantMap BatterySource::initialData(const QString &_source) const void BatterySource::run() { - // swap data - m_previousValues.swap(m_values); - // adaptor QFile acFile(QString("%1/AC/online").arg(m_acpiPath)); if (acFile.open(QIODevice::ReadOnly | QIODevice::Text)) @@ -175,9 +175,11 @@ void BatterySource::run() // current level QFile currentLevelFile( QString("%1/BAT%2/energy_now").arg(m_acpiPath).arg(i)); - if (currentLevelFile.open(QIODevice::ReadOnly | QIODevice::Text)) - m_values[QString("battery/batnow%1").arg(i)] - = QString(currentLevelFile.readLine()).toInt(); + if (currentLevelFile.open(QIODevice::ReadOnly | QIODevice::Text)) { + auto value = QString(currentLevelFile.readLine()).toInt(); + m_trend[i + 1].append(value); + m_values[QString("battery/batnow%1").arg(i)] = value; + } currentLevelFile.close(); // total QFile fullLevelFile( @@ -196,6 +198,7 @@ void BatterySource::run() } // total + m_trend[0].append(static_cast(currentLevel)); m_values["battery/batnow"] = static_cast(currentLevel); m_values["battery/battotal"] = static_cast(fullLevel); m_values["battery/bat"] = static_cast(100 * currentLevel / fullLevel); @@ -210,42 +213,56 @@ QStringList BatterySource::sources() const } +double BatterySource::approximate(const QList &_trend) +{ + qCDebug(LOG_ESS) << "Approximate by MSD" << _trend; + + auto count = _trend.count(); + + auto sumxy = 0; + for (int i = 0; i < count; i++) + sumxy += _trend.at(i) * (i + 1); + + auto sumx = count * (count + 1) / 2; + auto sumy = std::accumulate(_trend.cbegin(), _trend.cend(), 0); + auto sumx2 = count * (count + 1) * (2 * count + 1) / 6; + + return (count * sumxy - sumx * sumy) / (count * sumx2 - std::pow(sumx, 2)); +} + + void BatterySource::calculateRates() { - // we are using moving average to get good numbers - // check time interval - auto now = QDateTime::currentDateTimeUtc(); - auto interval - = 1000 * (now.toMSecsSinceEpoch() - m_timestamp.toMSecsSinceEpoch()); - m_timestamp.swap(now); - - // check time - if (m_previousValues.empty()) { - qCInfo(LOG_ESS) << "No historical data found for charges, exit"; + // check if it is first run + if (!m_timestamp.isValid()) { + m_timestamp = QDateTime::currentDateTimeUtc(); return; } - // per battery + // check time interval + auto now = QDateTime::currentDateTimeUtc(); + auto interval + = (now.toMSecsSinceEpoch() - m_timestamp.toMSecsSinceEpoch()) / 1000.0f; + m_timestamp.swap(now); + for (int i = 0; i < m_batteriesCount; i++) { - auto rate - = (m_values[QString("battery/batnow%1").arg(i)].toInt() - - m_previousValues[QString("battery/batnow%1").arg(i)].toInt()) - / interval; - m_values[QString("battery/batrate%1").arg(i)] - = (m_previousValues[QString("battery/batrate%1").arg(i)].toInt() - + rate) - / 2; + auto approx = approximate(m_trend[i + 1]); + m_values[QString("battery/batrate%1").arg(i)] = approx / interval; m_values[QString("battery/batleft%1").arg(i)] - = m_values[QString("battery/batnow%1").arg(i)].toInt() - / m_values[QString("battery/batrate%1").arg(i)].toInt(); + = interval * m_values[QString("battery/batnow%1").arg(i)].toFloat() + / approx; } // total - auto totalRate = (m_values["battery/batnow"].toInt() - - m_previousValues["battery/batnow"].toInt()) - / interval; - m_values["battery/batrate"] - = (totalRate + m_previousValues["battery/batrate"].toInt()) / 2; - m_values["battery/batleft"] = m_values["battery/batnow"].toInt() - / m_values["battery/batrate"].toInt(); + auto approx = approximate(m_trend[0]); + m_values["battery/batrate"] = approx / interval; + m_values["battery/batleft"] + = interval * m_values["battery/batnow"].toFloat() / approx; + + // old data cleanup + for (auto &trend : m_trend.keys()) { + if (m_trend[trend].count() <= TREND_LIMIT) + continue; + m_trend[trend].removeFirst(); + } } diff --git a/sources/extsysmonsources/batterysource.h b/sources/extsysmonsources/batterysource.h index 9840193..11763f3 100644 --- a/sources/extsysmonsources/batterysource.h +++ b/sources/extsysmonsources/batterysource.h @@ -29,6 +29,8 @@ class BatterySource : public AbstractExtSysMonSource Q_OBJECT public: + const int TREND_LIMIT = 20; + explicit BatterySource(QObject *_parent, const QStringList &_args); virtual ~BatterySource(); QStringList getSources(); @@ -38,14 +40,15 @@ public: QStringList sources() const; private: + double approximate(const QList &_trend); void calculateRates(); // configuration and values int m_batteriesCount = 0; QString m_acpiPath; QStringList m_sources; QDateTime m_timestamp; + QHash> m_trend; QVariantHash m_values; - QVariantHash m_previousValues; }; diff --git a/sources/version.h.in b/sources/version.h.in index 56d4ec4..ad4b040 100644 --- a/sources/version.h.in +++ b/sources/version.h.in @@ -59,9 +59,9 @@ const char STATIC_KEYS[] "gputemp,gpu,memmb,memgb,memfreemb,memfreegb,memtotmb,memtotgb,memusedmb," "memusedgb,mem,swapmb,swapgb,swapfreemb,swapfreegb,swaptotmb,swaptotgb," "swap,downunits,upunits,downkb,downtotkb,downtot,down,uptotkb,uptot,upkb," - "up,netdev,ac,bat,album,artist,duration,progress,title,dalbum,dartist," - "dtitle,salbum,sartist,stitle,pscount,pstot,ps,desktop,ndesktop," - "tdesktops,la15,la5,la1"; + "up,netdev,ac,bat,batleft,batnow,batrate,battotal,album,artist,duration," + "progress,title,dalbum,dartist,dtitle,salbum,sartist,stitle,pscount,pstot" + ",ps,desktop,ndesktop,tdesktops,la15,la5,la1"; #cmakedefine BUILD_FUTURE #cmakedefine BUILD_LOAD #cmakedefine BUILD_TESTING