Implement charger control and charger plugged in boolean

This commit is contained in:
Matti Viljanen 2020-03-20 17:26:29 +02:00
parent b429c474c6
commit c67a33a4b7
No known key found for this signature in database
GPG key ID: CF32A1495158F888
9 changed files with 302 additions and 91 deletions

1
.gitignore vendored
View file

@ -1,5 +1,6 @@
*.old *.old
*.bak *.bak
*.tmp
*.pro.user *.pro.user
*.pro.user.* *.pro.user.*
*.qm *.qm

View file

@ -22,7 +22,7 @@ Item {
id: batteryGraph id: batteryGraph
property real borderSize: width * 0.15 property real borderSize: width * 0.15
property real charge: battery.charge property real charge: battery.charge
property bool charging: battery.charging property bool chargerConnected: battery.chargerConnected
height: 1.75 * width height: 1.75 * width
Rectangle { Rectangle {

View file

@ -22,27 +22,33 @@ import "../components"
CoverBackground { CoverBackground {
id: coverPage id: coverPage
onStatusChanged: batteryGraph.updateView()
BatteryGraph { BatteryGraph {
id: batteryGraph id: batteryGraph
x: coverPage.width * 0.3 x: coverPage.width * 0.3
y: coverPage.width * 0.25 y: coverPage.width * 0.25
width: 0.4 * coverPage.width width: 0.4 * coverPage.width
onStateChanged: { updateView() } Component.onCompleted: updateView()
onChargingChanged: { updateView() } onStateChanged: updateView()
onChargeChanged: { updateView() } onChargerConnectedChanged: updateView()
onChargeChanged: updateView()
function updateView() { function updateView() {
if(charge <= settings.lowerLimit && battery.state === "discharging") { if(charge <= settings.lowerLimit && battery.state === "discharging") {
coverText.text = qsTr("Connect\ncharger") coverText.text = qsTr("Connect\ncharger")
} }
else if(battery.charge >= settings.upperLimit && else if(battery.charge >= settings.upperLimit &&
((battery.state === "charging" && battery.charging === true) || (battery.state === "idle" && battery.charging === false))) { (battery.state === "charging" || battery.state === "idle")) {
coverText.text = qsTr("Disconnect\ncharger") coverText.text = qsTr("Disconnect\ncharger")
} }
else if(battery.charging) { else if(battery.chargerConnected && battery.state === "charging") {
coverText.text = qsTr("Charging...") coverText.text = qsTr("Charging")
} }
else { else if(battery.chargerConnected && battery.state === "discharging") {
coverText.text = qsTr("Not charging")
}
else { // Discharging
coverText.text = qsTr("Battery\nBuddy") coverText.text = qsTr("Battery\nBuddy")
} }
} }

View file

@ -94,8 +94,8 @@ Page {
value: battery.charge + "%" value: battery.charge + "%"
} }
MyDetailItem { MyDetailItem {
label: qsTr("Charging:") label: qsTr("Charger connected:")
value: battery.charging ? qsTr("yes") : qsTr("no") value: battery.chargerConnected ? qsTr("yes") : qsTr("no")
} }
MyDetailItem { MyDetailItem {
label: qsTr("State:") label: qsTr("State:")

View file

@ -20,7 +20,10 @@ import Sailfish.Silica 1.0
Page { Page {
id: settingsPage id: settingsPage
SilicaFlickable {
anchors.fill: parent anchors.fill: parent
contentHeight: header.height + settingsColumn.height + Theme.horizontalPageMargin
PageHeader { PageHeader {
id: header id: header
@ -28,8 +31,13 @@ Page {
} }
Column { Column {
anchors.top: header.bottom id: settingsColumn
width: parent.width anchors {
top: header.bottom
left: parent.left
right: parent.right
}
spacing: Theme.paddingMedium spacing: Theme.paddingMedium
Label { Label {
@ -37,34 +45,6 @@ Page {
text: qsTr("Alert settings") text: qsTr("Alert settings")
color: Theme.highlightColor color: Theme.highlightColor
} }
Label {
x: Theme.paddingLarge*2
width: parent.width - x*2;
wrapMode: Text.Wrap
text: qsTr("Set the maximum and minimum target charge levels.")
color: Theme.primaryColor
font.pixelSize: Theme.fontSizeSmall
}
Slider {
width: parent.width
label: qsTr("Charging limit")
minimumValue: 60
maximumValue: 99
stepSize: 1
value: settings.upperLimit
valueText: value + "%"
onValueChanged: settings.upperLimit = value
}
Slider {
width: parent.width
label: qsTr("Discharging limit")
minimumValue: 10
maximumValue: 40
stepSize: 1
value: settings.lowerLimit
valueText: value + "%"
onValueChanged: settings.lowerLimit = value
}
Slider { Slider {
width: parent.width width: parent.width
label: qsTr("Alert interval") label: qsTr("Alert interval")
@ -75,6 +55,136 @@ Page {
valueText: Math.floor(value / 60) + (value % 60 < 10 ? ":0" + value % 60 : ":" + value % 60) valueText: Math.floor(value / 60) + (value % 60 < 10 ? ":0" + value % 60 : ":" + value % 60)
onValueChanged: settings.interval = value onValueChanged: settings.interval = value
} }
Label {
x: Theme.paddingLarge*2
width: parent.width - x*2;
wrapMode: Text.Wrap
text: qsTr("Set the maximum and minimum target charge levels.")
color: Theme.primaryColor
font.pixelSize: Theme.fontSizeSmall
}
Slider {
id: upperChargeLimit
width: parent.width
label: qsTr("Charging limit")
minimumValue: 60
maximumValue: 99
stepSize: 1
value: settings.upperLimit
valueText: value + "%"
onValueChanged: {
settings.upperLimit = value
if((value - 2) < continueChargeLimit.value)
continueChargeLimit.value = value - 2
}
}
Slider {
width: parent.width
label: qsTr("Discharging limit")
minimumValue: 10
maximumValue: 40
stepSize: 1
value: settings.lowerLimit
valueText: value + "%"
onValueChanged: settings.lowerLimit = value
}
TextSwitch {
id: autoStopCharging
text: qsTr("Stop charging when limit reached")
description: qsTr("This option stops charging when battery has reached the percentage set in Charging limit value, and resumes charging when charge has decreased below Continue charge limit value. Generally a value close to the Charging limit value is recommened, such as 80% and 75%.")
checked: settings.limitEnabled
onCheckedChanged: settings.limitEnabled = checked
}
Slider {
id: continueChargeLimit
handleVisible: enabled
width: parent.width
label: qsTr("Resume charging limit")
minimumValue: 50
maximumValue: upperChargeLimit.value - 2
stepSize: 1
value: settings.chargeLimit
valueText: value + "%"
onValueChanged: settings.chargeLimit = value
}
Label {
x: Theme.paddingLarge*2
width: parent.width - x*2;
wrapMode: Text.Wrap
text: qsTr("You can also independently stop and resume charging.")
color: Theme.primaryColor
font.pixelSize: Theme.fontSizeSmall
}
Row {
anchors {
left: parent.left
right: parent.right
}
height: button.height
Column {
width: parent.width / 2
Button {
id: button
anchors.horizontalCenter: parent.horizontalCenter
text: qsTr("Enable")
onClicked: battery.chargingEnabled = true
}
}
Column {
width: parent.width / 2
Button {
anchors.horizontalCenter: parent.horizontalCenter
text: qsTr("Disable")
onClicked: battery.chargingEnabled = false
}
}
}
Label {
x: Theme.paddingLarge
text: qsTr("Alert tests")
color: Theme.highlightColor
}
Label {
x: Theme.paddingLarge*2
width: parent.width - x*2;
wrapMode: Text.Wrap
text: qsTr("Click the buttons to test the sound and notification.")
color: Theme.primaryColor
font.pixelSize: Theme.fontSizeSmall
}
Row {
anchors {
left: parent.left
right: parent.right
}
height: button.height
Column {
width: parent.width / 2
Button {
anchors.horizontalCenter: parent.horizontalCenter
text: qsTr("Charged")
onClicked: {
alertHigh.play()
notification.republishTest()
}
}
}
Column {
width: parent.width / 2
Button {
anchors.horizontalCenter: parent.horizontalCenter
text: qsTr("Discharged")
onClicked: {
alertLow.play()
notification.republishTest()
}
}
}
}
}
} }
} }

View file

@ -20,11 +20,36 @@
Battery::Battery(QObject* parent) : QObject(parent) Battery::Battery(QObject* parent) : QObject(parent)
{ {
// Number: meaning percentage, e.g. 42 // Number: meaning percentage, e.g. 42
chargeFile = new QFile("/run/state/namespaces/Battery/ChargePercentage", this); chargeFile = new QFile("/sys/class/power_supply/battery/capacity", this);
// Number: 0 or 1
chargingFile = new QFile("/run/state/namespaces/Battery/IsCharging", this);
// String: charging, discharging, (empty), unknown (others?) // String: charging, discharging, (empty), unknown (others?)
stateFile = new QFile("/run/state/namespaces/Battery/ChargingState", this); stateFile = new QFile("/sys/class/power_supply/battery/status", this);
// Number: 0 or 1
chargerConnectedFile = new QFile("/sys/class/power_supply/usb/present");
// ENABLE/DISABLE CHARGING
// e.g. for Sony Xperia XA2
if(QFile::exists(QString("/sys/class/power_supply/battery/input_suspend"))) {
chargingEnabledFile = new QFile("/sys/class/power_supply/battery/input_suspend");
enableChargingValue = 0;
disableChargingValue = 1;
}
// e.g. for Sony Xperia Z3 Compact Tablet
else if(QFile::exists(QString("/sys/class/power_supply/battery/charging_enabled"))) {
chargingEnabledFile = new QFile("/sys/class/power_supply/battery/charging_enabled");
enableChargingValue = 1;
disableChargingValue = 0;
}
// e.g. for Jolla Phone
else if(QFile::exists(QString("/sys/class/power_supply/usb/charger_disable"))) {
chargingEnabledFile = new QFile("/sys/class/power_supply/usb/charger_disable");
enableChargingValue = 0;
disableChargingValue = 1;
}
else
chargingEnabledFile = Q_NULLPTR;
// TODO // TODO
// Implement DBus mechanism for reading battery status // Implement DBus mechanism for reading battery status
@ -37,33 +62,58 @@ Battery::~Battery() { }
void Battery::updateData() void Battery::updateData()
{ {
if(chargeFile->open(QIODevice::ReadOnly)) { if(chargeFile->open(QIODevice::ReadOnly)) {
nextCharge = chargeFile->readAll().toInt(); nextCharge = chargeFile->readLine().trimmed().toInt();
if(nextCharge != charge) { if(nextCharge != charge) {
charge = nextCharge; charge = nextCharge;
emit chargeChanged(); emit chargeChanged();
} }
chargeFile->close(); chargeFile->close();
} }
if(chargingFile->open(QIODevice::ReadOnly)) { if(chargerConnectedFile->open(QIODevice::ReadOnly)) {
nextCharging = (chargingFile->readAll().toInt() == 0 ? false : true); nextChargerConnected = chargerConnectedFile->readLine().trimmed().toInt();
if(nextCharging != charging) { if(nextChargerConnected != chargerConnected) {
charging = nextCharging; chargerConnected = nextChargerConnected;
emit chargingChanged(); emit chargerConnectedChanged();
} }
chargingFile->close(); chargerConnectedFile->close();
} }
if(stateFile->open(QIODevice::ReadOnly)) { if(stateFile->open(QIODevice::ReadOnly)) {
nextState = (QString(stateFile->readAll())); nextState = (QString(stateFile->readLine().trimmed().toLower()));
if(nextState != state) { if(nextState != state) {
state = nextState; state = nextState;
emit stateChanged(); emit stateChanged();
} }
stateFile->close(); stateFile->close();
} }
// This can't be used, because on Jolla Phone the file always reads "0" :(
// It doesn't matter that much anyway, because the value changes only when we change it.
// if(chargingEnabledFile && chargingEnabledFile->open(QIODevice::ReadOnly)) {
// nextChargingEnabled = chargingEnabledFile->readLine().trimmed().toInt() == enableChargingValue;
// if(nextChargingEnabled != chargingEnabled) {
// chargingEnabled = nextChargingEnabled;
// emit chargingEnabledChanged();
// }
// chargingEnabledFile->close();
// }
} }
int Battery::getCharge(){ return charge; } int Battery::getCharge(){ return charge; }
bool Battery::getCharging() { return charging; }
QString Battery::getState() { return state; } QString Battery::getState() { return state; }
bool Battery::getChargingEnabled() { return chargingEnabled; }
void Battery::setChargingEnabled(bool isEnabled) {
if(chargingEnabledFile && chargingEnabledFile->open(QIODevice::WriteOnly)) {
if(chargingEnabledFile->write(QString("%1").arg(isEnabled ? enableChargingValue : disableChargingValue).toLatin1())) {
chargingEnabled = isEnabled;
emit chargingEnabledChanged();
}
chargingEnabledFile->close();
}
}
bool Battery::getChargerConnected() {
return chargerConnected;
}

View file

@ -25,9 +25,10 @@
class Battery : public QObject class Battery : public QObject
{ {
Q_OBJECT Q_OBJECT
Q_PROPERTY(int charge READ getCharge NOTIFY chargeChanged ) Q_PROPERTY(int charge READ getCharge NOTIFY chargeChanged)
Q_PROPERTY(bool charging READ getCharging NOTIFY chargingChanged) Q_PROPERTY(bool chargerConnected READ getChargerConnected NOTIFY chargerConnectedChanged)
Q_PROPERTY(QString state READ getState NOTIFY stateChanged) Q_PROPERTY(QString state READ getState NOTIFY stateChanged)
Q_PROPERTY(bool chargingEnabled READ getChargingEnabled WRITE setChargingEnabled NOTIFY chargingEnabledChanged)
public: public:
Battery(QObject* parent = nullptr); Battery(QObject* parent = nullptr);
@ -35,29 +36,40 @@ public:
int getCharge(); int getCharge();
bool getCharging(); bool getCharging();
bool getChargerConnected();
QString getState(); QString getState();
bool getChargingEnabled();
void setChargingEnabled(bool);
public slots: public slots:
void updateData(); void updateData();
private: private:
QFile* chargeFile; QFile* chargeFile;
QFile* chargingFile; QFile* chargerConnectedFile;
QFile* stateFile; QFile* stateFile;
QFile* chargingEnabledFile;
// Default values: // Default values:
int charge = 100; // 100% full int charge = 100; // 100% full
bool charging = true; // Charger plugged in bool chargerConnected = false; // Charger plugged in
QString state = "idle"; // dis/charging, idle, unknown QString state = "idle"; // dis/charging, idle, unknown
bool chargingEnabled = true; // Only ever disabled manually
int enableChargingValue = 1;
int disableChargingValue = 0;
int nextCharge = charge; int nextCharge = charge;
bool nextCharging = charging; bool nextChargerConnected = chargerConnected;
QString nextState = state; QString nextState = state;
bool nextChargingEnabled = chargingEnabled;
signals: signals:
int chargeChanged(); int chargeChanged();
bool chargingChanged();
QString stateChanged(); QString stateChanged();
bool chargingEnabledChanged();
bool chargerConnectedChanged();
}; };
#endif // BATTERY_H #endif // BATTERY_H

View file

@ -41,13 +41,27 @@ Settings::Settings(QObject *parent) : QObject(parent)
emit intervalChanged(); emit intervalChanged();
} }
} }
if(mySettings.contains("limitEnabled")) {
limitEnabled = (mySettings.value("limitEnabled").toInt() == 1);
emit limitEnabledChanged();
}
if(mySettings.contains("chargeLimit")) {
tempValue = mySettings.value("chargeLimit").toInt();
if(tempValue >= 50 && tempValue <= (upperLimit - 2)) {
chargeLimit = tempValue;
emit chargeLimitChanged();
}
}
} }
Settings::~Settings() Settings::~Settings()
{ {
int limitValue = limitEnabled ? 1 : 0;
mySettings.setValue("lowerLimit", QByteArray::number(lowerLimit)); mySettings.setValue("lowerLimit", QByteArray::number(lowerLimit));
mySettings.setValue("upperLimit", QByteArray::number(upperLimit)); mySettings.setValue("upperLimit", QByteArray::number(upperLimit));
mySettings.setValue("interval", QByteArray::number(interval)); mySettings.setValue("interval", QByteArray::number(interval));
mySettings.setValue("limitEnabled", QByteArray::number(limitValue));
mySettings.setValue("chargeLimit", QByteArray::number(chargeLimit));
} }
int Settings::getLowerLimit() { return lowerLimit; } int Settings::getLowerLimit() { return lowerLimit; }
@ -60,8 +74,16 @@ QString Settings::getLowAlert() { return lowAlertFile; }
QString Settings::getHighAlert() { return highAlertFile; } QString Settings::getHighAlert() { return highAlertFile; }
bool Settings::getLimitEnabled() { return limitEnabled; }
int Settings::getChargeLimit() { return chargeLimit; }
void Settings::setLowerLimit(int newLimit) { lowerLimit = newLimit; } void Settings::setLowerLimit(int newLimit) { lowerLimit = newLimit; }
void Settings::setUpperLimit(int newLimit) { upperLimit = newLimit; } void Settings::setUpperLimit(int newLimit) { upperLimit = newLimit; }
void Settings::setInterval(int newInterval) { interval = newInterval; } void Settings::setInterval(int newInterval) { interval = newInterval; }
void Settings::setLimitEnabled(bool newEnabled) { limitEnabled = newEnabled; }
void Settings::setChargeLimit(int newLimit) { chargeLimit = newLimit; }

View file

@ -27,6 +27,8 @@ class Settings : public QObject
Q_PROPERTY(int lowerLimit READ getLowerLimit WRITE setLowerLimit NOTIFY lowerLimitChanged) Q_PROPERTY(int lowerLimit READ getLowerLimit WRITE setLowerLimit NOTIFY lowerLimitChanged)
Q_PROPERTY(int upperLimit READ getUpperLimit WRITE setUpperLimit NOTIFY upperLimitChanged) Q_PROPERTY(int upperLimit READ getUpperLimit WRITE setUpperLimit NOTIFY upperLimitChanged)
Q_PROPERTY(int interval READ getInterval WRITE setInterval NOTIFY intervalChanged) Q_PROPERTY(int interval READ getInterval WRITE setInterval NOTIFY intervalChanged)
Q_PROPERTY(bool limitEnabled READ getLimitEnabled WRITE setLimitEnabled NOTIFY limitEnabledChanged)
Q_PROPERTY(int chargeLimit READ getChargeLimit WRITE setChargeLimit NOTIFY chargeLimitChanged)
Q_PROPERTY(QString lowAlertFile READ getLowAlert NOTIFY lowAlertChanged) Q_PROPERTY(QString lowAlertFile READ getLowAlert NOTIFY lowAlertChanged)
Q_PROPERTY(QString highAlertFile READ getHighAlert NOTIFY highAlertChanged) Q_PROPERTY(QString highAlertFile READ getHighAlert NOTIFY highAlertChanged)
@ -38,11 +40,15 @@ public:
int getLowerLimit(); int getLowerLimit();
int getUpperLimit(); int getUpperLimit();
int getInterval(); int getInterval();
bool getLimitEnabled();
int getChargeLimit();
QString getLowAlert(); QString getLowAlert();
QString getHighAlert(); QString getHighAlert();
void setLowerLimit(int newLimit); void setLowerLimit(int newLimit);
void setUpperLimit(int newLimit); void setUpperLimit(int newLimit);
void setInterval(int newInterval); void setInterval(int newInterval);
void setLimitEnabled(bool newEnabled);
void setChargeLimit(int newLimit);
private: private:
QSettings mySettings; QSettings mySettings;
@ -51,6 +57,8 @@ private:
int lowerLimit = 25; int lowerLimit = 25;
int upperLimit = 75; int upperLimit = 75;
int interval = 60; int interval = 60;
bool limitEnabled = false;
int chargeLimit = 70;
QString lowAlertFile = "/usr/share/sounds/jolla-ambient/stereo/general_warning.wav"; QString lowAlertFile = "/usr/share/sounds/jolla-ambient/stereo/general_warning.wav";
QString highAlertFile = "/usr/share/sounds/jolla-ambient/stereo/positive_confirmation.wav"; QString highAlertFile = "/usr/share/sounds/jolla-ambient/stereo/positive_confirmation.wav";
@ -58,6 +66,8 @@ signals:
int lowerLimitChanged(); int lowerLimitChanged();
int upperLimitChanged(); int upperLimitChanged();
int intervalChanged(); int intervalChanged();
bool limitEnabledChanged();
int chargeLimitChanged();
QString lowAlertChanged(); QString lowAlertChanged();
QString highAlertChanged(); QString highAlertChanged();
}; };