2020-04-26 11:30:30 +03:00
|
|
|
/**
|
|
|
|
* Battery Buddy, a Sailfish application to prolong battery lifetime
|
|
|
|
*
|
|
|
|
* Copyright (C) 2019-2020 Matti Viljanen
|
|
|
|
*
|
|
|
|
* Battery Buddy is free software: you can redistribute it and/or modify it under the terms of the
|
|
|
|
* GNU General Public License as published by the Free Software Foundation, either version 3 of the
|
|
|
|
* License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* Battery Buddy is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
|
|
|
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
*
|
|
|
|
* See the GNU General Public License for more details. You should have received a copy of the GNU
|
|
|
|
* General Public License along with Battery Buddy. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*
|
|
|
|
* Author: Matti Viljanen
|
|
|
|
*/
|
|
|
|
#include "battery.h"
|
|
|
|
|
2021-04-24 18:14:26 +03:00
|
|
|
Battery::Battery(Logger* newLogger, bool loglevelSet, QObject *parent) : QObject(parent)
|
2020-04-26 11:30:30 +03:00
|
|
|
{
|
2021-04-17 22:01:19 +03:00
|
|
|
logger = newLogger;
|
|
|
|
settings = new Settings(logger, this);
|
2021-04-24 18:14:26 +03:00
|
|
|
|
|
|
|
// Read log level from config - if not already set
|
|
|
|
if(!loglevelSet) {
|
|
|
|
int logLevel = settings->getLogLevel();
|
|
|
|
logger->debug = (logLevel == 2);
|
|
|
|
logger->verbose = (logLevel > 1);
|
2021-04-24 18:27:37 +03:00
|
|
|
logE(QString("Log level set to %1").arg((logLevel == 0 ? "low" : (logLevel == 1 ? "medium" : "high"))));
|
2021-04-24 18:14:26 +03:00
|
|
|
}
|
|
|
|
|
2020-06-14 19:22:41 +03:00
|
|
|
updateTimer = new QTimer(this);
|
|
|
|
highNotifyTimer = new QTimer(this);
|
|
|
|
lowNotifyTimer = new QTimer(this);
|
2021-04-18 13:55:30 +03:00
|
|
|
notification = new MyNotification(this);
|
2020-04-26 11:30:30 +03:00
|
|
|
|
|
|
|
// Number: charge percentage, e.g. 42
|
|
|
|
chargeFile = new QFile("/sys/class/power_supply/battery/capacity", this);
|
2021-04-24 18:27:37 +03:00
|
|
|
logE("Capacity file: " + chargeFile->fileName());
|
2020-04-26 11:30:30 +03:00
|
|
|
|
|
|
|
// String: charging, discharging, full, empty, unknown (others?)
|
|
|
|
stateFile = new QFile("/sys/class/power_supply/battery/status", this);
|
2021-04-24 18:27:37 +03:00
|
|
|
logE("Charge state file: " + stateFile->fileName());
|
2020-04-26 11:30:30 +03:00
|
|
|
|
|
|
|
// Number: 0 or 1
|
|
|
|
chargerConnectedFile = new QFile("/sys/class/power_supply/usb/present", this);
|
2021-04-24 18:27:37 +03:00
|
|
|
logE("Charger status file: " + chargerConnectedFile->fileName());
|
2020-04-26 11:30:30 +03:00
|
|
|
|
|
|
|
// ENABLE/DISABLE CHARGING
|
2021-04-24 18:14:26 +03:00
|
|
|
QString filename;
|
2021-04-26 17:13:11 +03:00
|
|
|
|
2020-04-26 11:30:30 +03:00
|
|
|
// e.g. for Sony Xperia XA2
|
|
|
|
filename = "/sys/class/power_supply/battery/input_suspend";
|
|
|
|
if(!chargingEnabledFile && QFile::exists(filename)) {
|
|
|
|
chargingEnabledFile = new QFile(filename, this);
|
|
|
|
enableChargingValue = 0;
|
|
|
|
disableChargingValue = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// e.g. for Sony Xperia Z3 Compact Tablet
|
|
|
|
filename = "/sys/class/power_supply/battery/charging_enabled";
|
|
|
|
if(!chargingEnabledFile && QFile::exists(filename)) {
|
|
|
|
chargingEnabledFile = new QFile(filename, this);
|
|
|
|
enableChargingValue = 1;
|
|
|
|
disableChargingValue = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// e.g. for Jolla Phone
|
|
|
|
filename = "/sys/class/power_supply/usb/charger_disable";
|
|
|
|
if(!chargingEnabledFile && QFile::exists(filename)) {
|
|
|
|
chargingEnabledFile = new QFile(filename, this);
|
|
|
|
enableChargingValue = 0;
|
|
|
|
disableChargingValue = 1;
|
|
|
|
}
|
|
|
|
|
2021-04-26 17:13:11 +03:00
|
|
|
if(!chargingEnabledFile && QHostInfo::localHostName().contains("SailfishEmul")) {
|
2021-04-17 23:42:22 +03:00
|
|
|
logE("Charger control file not found!");
|
|
|
|
logE("Please contact the developer with your device model!");
|
2020-04-26 11:30:30 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// If we found a usable file, check that it is writable
|
2020-06-12 14:16:46 +03:00
|
|
|
if(chargingEnabledFile) {
|
2021-04-24 18:27:37 +03:00
|
|
|
logE("Charger control file: " + chargingEnabledFile->fileName());
|
2020-06-12 14:16:46 +03:00
|
|
|
if(chargingEnabledFile->open(QIODevice::WriteOnly)) {
|
|
|
|
chargingEnabledFile->close();
|
|
|
|
}
|
|
|
|
else {
|
2021-04-17 23:42:22 +03:00
|
|
|
logE("Charger control file is not writable!");
|
2020-06-12 14:16:46 +03:00
|
|
|
}
|
2020-04-26 11:30:30 +03:00
|
|
|
}
|
|
|
|
|
2020-04-26 18:20:28 +03:00
|
|
|
connect(updateTimer, SIGNAL(timeout()), this, SLOT(updateData()));
|
2020-11-30 23:33:27 +03:00
|
|
|
connect(settings, SIGNAL(resetTimers()), this, SLOT(resetTimers()));
|
2020-06-14 19:22:41 +03:00
|
|
|
connect(highNotifyTimer, SIGNAL(timeout()), this, SLOT(showHighNotification()));
|
|
|
|
connect(lowNotifyTimer, SIGNAL(timeout()), this, SLOT(showLowNotification()));
|
2020-04-26 18:20:28 +03:00
|
|
|
|
2020-11-30 23:41:09 +03:00
|
|
|
updateData();
|
2020-11-30 22:27:57 +03:00
|
|
|
updateTimer->start(5000);
|
2020-12-27 17:21:15 +03:00
|
|
|
|
|
|
|
// If updateData() didn't start the timers
|
|
|
|
// aka. "charging" status didn't change
|
|
|
|
// (or if both times are disabled, actually)
|
|
|
|
// manually trigger the timer startup.
|
|
|
|
if(!highNotifyTimer->isActive() && !lowNotifyTimer->isActive()) {
|
|
|
|
resetTimers();
|
|
|
|
}
|
2020-04-26 11:30:30 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
Battery::~Battery() { }
|
|
|
|
|
|
|
|
void Battery::updateData()
|
|
|
|
{
|
|
|
|
if(chargeFile->open(QIODevice::ReadOnly)) {
|
|
|
|
nextCharge = chargeFile->readLine().trimmed().toInt();
|
|
|
|
if(nextCharge != charge) {
|
|
|
|
charge = nextCharge;
|
|
|
|
emit chargeChanged(charge);
|
2021-04-17 23:42:22 +03:00
|
|
|
logV(QString("Battery: %1%").arg(charge));
|
2020-04-26 11:30:30 +03:00
|
|
|
}
|
|
|
|
chargeFile->close();
|
|
|
|
}
|
|
|
|
if(chargerConnectedFile->open(QIODevice::ReadOnly)) {
|
|
|
|
nextChargerConnected = chargerConnectedFile->readLine().trimmed().toInt();
|
|
|
|
if(nextChargerConnected != chargerConnected) {
|
|
|
|
chargerConnected = nextChargerConnected;
|
|
|
|
emit chargerConnectedChanged(chargerConnected);
|
2021-04-17 23:42:22 +03:00
|
|
|
logV(QString("Charger was %1").arg(chargerConnected ? "connected" : "disconnected"));
|
2020-04-26 11:30:30 +03:00
|
|
|
}
|
|
|
|
chargerConnectedFile->close();
|
|
|
|
}
|
|
|
|
if(stateFile->open(QIODevice::ReadOnly)) {
|
|
|
|
nextState = (QString(stateFile->readLine().trimmed().toLower()));
|
|
|
|
if(nextState != state) {
|
|
|
|
state = nextState;
|
|
|
|
emit stateChanged(state);
|
2021-04-24 18:27:37 +03:00
|
|
|
logV("Charging state: " + state);
|
2020-12-27 17:21:15 +03:00
|
|
|
|
|
|
|
// Hide/show notification right away
|
|
|
|
resetTimers();
|
2020-04-26 11:30:30 +03:00
|
|
|
}
|
|
|
|
stateFile->close();
|
|
|
|
}
|
2021-04-24 18:27:37 +03:00
|
|
|
|
2020-04-26 11:30:30 +03:00
|
|
|
if(chargingEnabledFile && settings->getLimitEnabled()) {
|
|
|
|
if(chargingEnabled && charge >= settings->getHighLimit()) {
|
2021-04-24 18:27:37 +03:00
|
|
|
logD("Disabling charging...");
|
2020-04-26 11:30:30 +03:00
|
|
|
setChargingEnabled(false);
|
|
|
|
}
|
|
|
|
else if(!chargingEnabled && charge <= settings->getLowLimit()) {
|
2021-04-24 18:27:37 +03:00
|
|
|
logD("Enabling charging...");
|
2020-04-26 11:30:30 +03:00
|
|
|
setChargingEnabled(true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-30 23:33:27 +03:00
|
|
|
void Battery::resetTimers() {
|
2020-06-14 19:22:41 +03:00
|
|
|
highNotifyTimer->stop();
|
|
|
|
lowNotifyTimer->stop();
|
|
|
|
highNotifyTimer->setInterval(settings->getHighNotificationsInterval() * 1000);
|
|
|
|
lowNotifyTimer->setInterval(settings->getLowNotificationsInterval() * 1000);
|
2021-04-17 23:42:22 +03:00
|
|
|
|
2020-11-30 23:41:09 +03:00
|
|
|
if(settings->getHighNotificationsInterval() < 610) {
|
2021-04-17 23:42:22 +03:00
|
|
|
logD("Starting high battery timer");
|
2020-11-30 23:41:09 +03:00
|
|
|
highNotifyTimer->start();
|
2020-12-01 01:53:48 +03:00
|
|
|
showHighNotification();
|
2020-11-30 23:41:09 +03:00
|
|
|
}
|
|
|
|
else {
|
2021-04-17 23:42:22 +03:00
|
|
|
logD("High battery timer not started");
|
2020-11-30 23:41:09 +03:00
|
|
|
}
|
2021-04-17 23:42:22 +03:00
|
|
|
|
2020-11-30 23:41:09 +03:00
|
|
|
if(settings->getLowNotificationsInterval() < 610) {
|
2021-04-17 23:42:22 +03:00
|
|
|
logD("Start low battery timer");
|
2020-11-30 23:41:09 +03:00
|
|
|
lowNotifyTimer->start();
|
2020-12-01 01:53:48 +03:00
|
|
|
showLowNotification();
|
2020-11-30 23:41:09 +03:00
|
|
|
}
|
|
|
|
else {
|
2021-04-17 23:42:22 +03:00
|
|
|
logD("Low battery timer not started");
|
2020-11-30 23:41:09 +03:00
|
|
|
}
|
2020-04-26 18:20:28 +03:00
|
|
|
}
|
|
|
|
|
2020-06-14 19:22:41 +03:00
|
|
|
void Battery::showHighNotification() {
|
2020-11-30 23:58:37 +03:00
|
|
|
if(settings->getHighNotificationsInterval() < 610 && (charge >= settings->getHighAlert() && state != "discharging")
|
2020-06-14 19:22:41 +03:00
|
|
|
&& !(charge == 100 && state == "idle")) {
|
2021-04-24 18:27:37 +03:00
|
|
|
logV(QString("Notification: %1").arg(settings->getNotificationTitle().arg(charge)));
|
2020-06-14 19:22:41 +03:00
|
|
|
notification->send(settings->getNotificationTitle().arg(charge), settings->getNotificationHighText(), settings->getHighAlertFile());
|
2020-12-01 01:53:48 +03:00
|
|
|
if(settings->getHighNotificationsInterval() == 50) {
|
2021-04-17 23:42:22 +03:00
|
|
|
logD("Stop high battery timer");
|
2020-11-30 23:41:09 +03:00
|
|
|
highNotifyTimer->stop();
|
|
|
|
}
|
2020-06-14 19:22:41 +03:00
|
|
|
}
|
2020-12-27 03:10:34 +03:00
|
|
|
else if(charge > settings->getLowAlert()) {
|
2021-04-17 23:42:22 +03:00
|
|
|
logD("Close high battery notification");
|
2020-06-14 19:22:41 +03:00
|
|
|
notification->close();
|
|
|
|
}
|
|
|
|
}
|
2020-04-26 18:20:28 +03:00
|
|
|
|
2020-06-14 19:22:41 +03:00
|
|
|
void Battery::showLowNotification() {
|
2021-04-24 18:27:37 +03:00
|
|
|
logD(QString("Low notification if %1% < %2%)").arg(charge).arg(settings->getLowAlert()));
|
2020-11-30 23:58:37 +03:00
|
|
|
if(settings->getLowNotificationsInterval() < 610 && charge <= settings->getLowAlert() && state != "charging") {
|
2021-04-24 18:27:37 +03:00
|
|
|
logV(QString("Notification: %1").arg(settings->getNotificationTitle().arg(charge)));
|
2020-04-26 18:20:28 +03:00
|
|
|
notification->send(settings->getNotificationTitle().arg(charge), settings->getNotificationLowText(), settings->getLowAlertFile());
|
2020-11-30 23:41:09 +03:00
|
|
|
if(settings->getLowNotificationsInterval() == 50) {
|
2021-04-17 23:42:22 +03:00
|
|
|
logD("Stop low battery timer");
|
2020-11-30 23:41:09 +03:00
|
|
|
lowNotifyTimer->stop();
|
|
|
|
}
|
2020-04-26 18:20:28 +03:00
|
|
|
}
|
2020-12-27 03:10:34 +03:00
|
|
|
else if(charge < settings->getHighAlert()) {
|
2021-04-17 23:42:22 +03:00
|
|
|
logD("Close low battery notification");
|
2020-04-26 18:20:28 +03:00
|
|
|
notification->close();
|
|
|
|
}
|
|
|
|
}
|
2020-06-14 19:22:41 +03:00
|
|
|
|
2020-04-26 18:20:28 +03:00
|
|
|
int Battery::getCharge() { return charge; }
|
2020-04-26 11:30:30 +03:00
|
|
|
|
|
|
|
QString Battery::getState() { return state; }
|
|
|
|
|
|
|
|
bool Battery::getChargingEnabled() { return chargingEnabled; }
|
|
|
|
|
2021-04-17 22:13:57 +03:00
|
|
|
bool Battery::setChargingEnabled(const bool isEnabled) {
|
2020-06-12 14:26:00 +03:00
|
|
|
bool success = false;
|
2020-06-12 14:16:46 +03:00
|
|
|
if(chargingEnabledFile) {
|
|
|
|
if(chargingEnabledFile->open(QIODevice::WriteOnly)) {
|
|
|
|
if(chargingEnabledFile->write(QString("%1").arg(isEnabled ? enableChargingValue : disableChargingValue).toLatin1())) {
|
|
|
|
chargingEnabled = isEnabled;
|
|
|
|
emit chargingEnabledChanged(chargingEnabled);
|
2020-06-12 14:26:00 +03:00
|
|
|
success = true;
|
2020-06-12 14:16:46 +03:00
|
|
|
|
|
|
|
if(isEnabled) {
|
2021-04-17 22:01:19 +03:00
|
|
|
logV("Charging resumed");
|
2020-06-12 14:16:46 +03:00
|
|
|
}
|
|
|
|
else {
|
2021-04-17 22:01:19 +03:00
|
|
|
logV("Charging paused");
|
2020-06-12 14:16:46 +03:00
|
|
|
}
|
2020-04-26 11:30:30 +03:00
|
|
|
}
|
|
|
|
else {
|
2021-04-17 23:42:22 +03:00
|
|
|
logE("Could not write new charger state");
|
2020-04-26 11:30:30 +03:00
|
|
|
}
|
2020-06-12 14:16:46 +03:00
|
|
|
chargingEnabledFile->close();
|
|
|
|
}
|
|
|
|
else {
|
2021-04-17 23:42:22 +03:00
|
|
|
logE("Could not open charger control file");
|
2020-04-26 11:30:30 +03:00
|
|
|
}
|
|
|
|
}
|
2020-06-12 14:26:00 +03:00
|
|
|
return success;
|
2020-04-26 11:30:30 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
bool Battery::getChargerConnected() {
|
|
|
|
return chargerConnected;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Battery::shutdown() {
|
2021-04-24 18:27:37 +03:00
|
|
|
logV("Service shut down...");
|
2020-04-26 18:20:28 +03:00
|
|
|
blockSignals(true);
|
|
|
|
if(updateTimer) {
|
|
|
|
updateTimer->stop();
|
2021-04-17 22:01:19 +03:00
|
|
|
logD("Update timer stopped");
|
2020-04-26 18:20:28 +03:00
|
|
|
}
|
2020-04-26 18:39:27 +03:00
|
|
|
notification->close();
|
2020-06-14 19:22:41 +03:00
|
|
|
if(highNotifyTimer) {
|
|
|
|
highNotifyTimer->stop();
|
2021-04-17 22:01:19 +03:00
|
|
|
logD("High battery notification stopped");
|
2020-06-14 19:22:41 +03:00
|
|
|
}
|
|
|
|
if(lowNotifyTimer) {
|
|
|
|
lowNotifyTimer->stop();
|
2021-04-17 22:01:19 +03:00
|
|
|
logD("Low battery notification stopped");
|
2020-04-26 18:39:27 +03:00
|
|
|
}
|
2021-04-09 23:34:06 +03:00
|
|
|
// ENABLE/DISABLE CHARGING
|
|
|
|
if(!QHostInfo::localHostName().contains("SailfishEmul") && !setChargingEnabled(true)) {
|
2021-04-17 23:42:22 +03:00
|
|
|
logE("ERROR! Could not restore charger status! Your device "
|
|
|
|
"may not charge until reboot! If that doesn't help, "
|
2021-04-17 22:01:19 +03:00
|
|
|
"uninstall Battery Buddy and reboot your device.");
|
2020-06-12 14:32:25 +03:00
|
|
|
}
|
2020-04-26 11:30:30 +03:00
|
|
|
}
|