1/*
2 SPDX-FileCopyrightText: 2009 Pino Toscano <pino@kde.org>
3 SPDX-FileCopyrightText: 2010, 2012, 2015 Lukáš Tinkl <ltinkl@redhat.com>
4 SPDX-FileCopyrightText: 2014 Kai Uwe Broulik <kde@privat.broulik.de>
5
6 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
7*/
8
9#include "upowerbattery.h"
10
11#include "upower.h"
12
13using namespace Solid::Backends::UPower;
14
15Battery::Battery(UPowerDevice *device)
16 : DeviceInterface(device)
17{
18 connect(sender: device, signal: &UPowerDevice::propertyChanged, context: this, slot: &Battery::slotChanged);
19
20 updateCache();
21}
22
23Battery::~Battery()
24{
25}
26
27bool Battery::isPresent() const
28{
29 return m_device.data()->prop(QStringLiteral("IsPresent")).toBool();
30}
31
32Solid::Battery::BatteryType Battery::type() const
33{
34 Solid::Battery::BatteryType result = Solid::Battery::UnknownBattery;
35 const auto t = static_cast<UpDeviceKind>(m_device.data()->prop(QStringLiteral("Type")).toUInt());
36 switch (t) {
37 case UP_DEVICE_KIND_LINE_POWER: // TODO
38 break;
39 case UP_DEVICE_KIND_BATTERY:
40 result = Solid::Battery::PrimaryBattery;
41 break;
42 case UP_DEVICE_KIND_UPS:
43 result = Solid::Battery::UpsBattery;
44 break;
45 case UP_DEVICE_KIND_MONITOR:
46 result = Solid::Battery::MonitorBattery;
47 break;
48 case UP_DEVICE_KIND_MOUSE:
49 result = Solid::Battery::MouseBattery;
50 break;
51 case UP_DEVICE_KIND_KEYBOARD:
52 result = Solid::Battery::KeyboardBattery;
53 break;
54 case UP_DEVICE_KIND_PDA:
55 result = Solid::Battery::PdaBattery;
56 break;
57 case UP_DEVICE_KIND_PHONE:
58 result = Solid::Battery::PhoneBattery;
59 break;
60 case UP_DEVICE_KIND_TABLET:
61 result = Solid::Battery::TabletBattery;
62 break;
63 case UP_DEVICE_KIND_GAMING_INPUT:
64 result = Solid::Battery::GamingInputBattery;
65 break;
66 case UP_DEVICE_KIND_HEADPHONES:
67 result = Solid::Battery::HeadphoneBattery;
68 break;
69 case UP_DEVICE_KIND_HEADSET:
70 result = Solid::Battery::HeadsetBattery;
71 break;
72 case UP_DEVICE_KIND_TOUCHPAD:
73 result = Solid::Battery::TouchpadBattery;
74 break;
75 case UP_DEVICE_KIND_BLUETOOTH_GENERIC:
76 result = Solid::Battery::BluetoothBattery;
77 break;
78 case UP_DEVICE_KIND_WEARABLE:
79 result = Solid::Battery::WearableBattery;
80 break;
81 case UP_DEVICE_KIND_UNKNOWN:
82 default:
83 break;
84 }
85
86 if (result == Solid::Battery::UnknownBattery) {
87 // Check if the battery came from Bluez, which is more useful than unknown battery type
88 // UP_DEVICE_KIND_BLUETOOTH_GENERIC is only in UPower 0.99.12
89 if (m_device.data()->prop(QStringLiteral("NativePath")).toString().startsWith(s: QLatin1String("/org/bluez/"))) {
90 result = Solid::Battery::BluetoothBattery;
91 }
92 }
93
94 return result;
95}
96
97int Battery::chargePercent() const
98{
99 return qRound(d: m_device.data()->prop(QStringLiteral("Percentage")).toDouble());
100}
101
102int Battery::capacity() const
103{
104 return qRound(d: m_device.data()->prop(QStringLiteral("Capacity")).toDouble());
105}
106
107int Battery::cycleCount() const
108{
109 // New in upower v0.99.14.
110 bool ok;
111 const int cycleCount = m_device.data()->prop(QStringLiteral("ChargeCycles")).toInt(ok: &ok);
112 if (ok) {
113 return cycleCount;
114 } else {
115 return -1;
116 }
117}
118
119bool Battery::isRechargeable() const
120{
121 return m_device.data()->prop(QStringLiteral("IsRechargeable")).toBool();
122}
123
124bool Battery::isPowerSupply() const
125{
126 return m_device.data()->prop(QStringLiteral("PowerSupply")).toBool();
127}
128
129Solid::Battery::ChargeState Battery::chargeState() const
130{
131 Solid::Battery::ChargeState result = Solid::Battery::NoCharge;
132 const UpDeviceState state = static_cast<UpDeviceState>(m_device.data()->prop(QStringLiteral("State")).toUInt());
133 switch (state) {
134 case UP_DEVICE_STATE_UNKNOWN:
135 result = Solid::Battery::NoCharge; // stable or unknown
136 break;
137 case UP_DEVICE_STATE_CHARGING:
138 result = Solid::Battery::Charging;
139 break;
140 case UP_DEVICE_STATE_DISCHARGING:
141 result = Solid::Battery::Discharging;
142 break;
143 case UP_DEVICE_STATE_EMPTY: // TODO "Empty"
144 break;
145 case UP_DEVICE_STATE_FULLY_CHARGED:
146 result = Solid::Battery::FullyCharged;
147 break;
148 case UP_DEVICE_STATE_PENDING_CHARGE: // TODO "Pending charge"
149 break;
150 case UP_DEVICE_STATE_PENDING_DISCHARGE: // TODO "Pending discharge"
151 break;
152 case UP_DEVICE_STATE_LAST:
153 break;
154 }
155 return result;
156}
157
158qlonglong Battery::timeToEmpty() const
159{
160 return m_device.data()->prop(QStringLiteral("TimeToEmpty")).toLongLong();
161}
162
163qlonglong Battery::timeToFull() const
164{
165 return m_device.data()->prop(QStringLiteral("TimeToFull")).toLongLong();
166}
167
168Solid::Battery::Technology Battery::technology() const
169{
170 const UpDeviceTechnology tech = static_cast<UpDeviceTechnology>(m_device.data()->prop(QStringLiteral("Technology")).toUInt());
171 switch (tech) {
172 case UP_DEVICE_TECHNOLOGY_UNKNOWN:
173 return Solid::Battery::UnknownTechnology;
174 case UP_DEVICE_TECHNOLOGY_LITHIUM_ION:
175 return Solid::Battery::LithiumIon;
176 case UP_DEVICE_TECHNOLOGY_LITHIUM_POLYMER:
177 return Solid::Battery::LithiumPolymer;
178 case UP_DEVICE_TECHNOLOGY_LITHIUM_IRON_PHOSPHATE:
179 return Solid::Battery::LithiumIronPhosphate;
180 case UP_DEVICE_TECHNOLOGY_LEAD_ACID:
181 return Solid::Battery::LeadAcid;
182 case UP_DEVICE_TECHNOLOGY_NICKEL_CADMIUM:
183 return Solid::Battery::NickelCadmium;
184 case UP_DEVICE_TECHNOLOGY_NICKEL_METAL_HYDRIDE:
185 return Solid::Battery::NickelMetalHydride;
186 case UP_DEVICE_TECHNOLOGY_LAST:
187 return Solid::Battery::UnknownTechnology;
188 }
189 return Solid::Battery::UnknownTechnology;
190}
191
192double Battery::energy() const
193{
194 return m_device.data()->prop(QStringLiteral("Energy")).toDouble();
195}
196
197double Battery::energyFull() const
198{
199 return m_device.data()->prop(QStringLiteral("EnergyFull")).toDouble();
200}
201
202double Battery::energyFullDesign() const
203{
204 return m_device.data()->prop(QStringLiteral("EnergyFullDesign")).toDouble();
205}
206
207double Battery::energyRate() const
208{
209 return m_device.data()->prop(QStringLiteral("EnergyRate")).toDouble();
210}
211
212double Battery::voltage() const
213{
214 return m_device.data()->prop(QStringLiteral("Voltage")).toDouble();
215}
216
217double Battery::temperature() const
218{
219 return m_device.data()->prop(QStringLiteral("Temperature")).toDouble();
220}
221
222QString Battery::serial() const
223{
224 return m_device.data()->prop(QStringLiteral("Serial")).toString();
225}
226
227qlonglong Battery::remainingTime() const
228{
229 if (chargeState() == Solid::Battery::Charging) {
230 return timeToFull();
231 } else if (chargeState() == Solid::Battery::Discharging) {
232 return timeToEmpty();
233 }
234
235 return -1;
236}
237
238void Battery::slotChanged()
239{
240 if (m_device) {
241 const bool old_isPresent = m_isPresent;
242 const int old_chargePercent = m_chargePercent;
243 const int old_capacity = m_capacity;
244 const int old_cycleCount = m_cycleCount;
245 const bool old_isPowerSupply = m_isPowerSupply;
246 const Solid::Battery::ChargeState old_chargeState = m_chargeState;
247 const qlonglong old_timeToEmpty = m_timeToEmpty;
248 const qlonglong old_timeToFull = m_timeToFull;
249 const double old_energy = m_energy;
250 const double old_energyFull = m_energyFull;
251 const double old_energyFullDesign = m_energyFullDesign;
252 const double old_energyRate = m_energyRate;
253 const double old_voltage = m_voltage;
254 const double old_temperature = m_temperature;
255 updateCache();
256
257 if (old_isPresent != m_isPresent) {
258 Q_EMIT presentStateChanged(newState: m_isPresent, udi: m_device.data()->udi());
259 }
260
261 if (old_chargePercent != m_chargePercent) {
262 Q_EMIT chargePercentChanged(value: m_chargePercent, udi: m_device.data()->udi());
263 }
264
265 if (old_capacity != m_capacity) {
266 Q_EMIT capacityChanged(value: m_capacity, udi: m_device.data()->udi());
267 }
268
269 if (old_cycleCount != m_cycleCount) {
270 Q_EMIT cycleCountChanged(value: m_cycleCount, udi: m_device.data()->udi());
271 }
272
273 if (old_isPowerSupply != m_isPowerSupply) {
274 Q_EMIT powerSupplyStateChanged(newState: m_isPowerSupply, udi: m_device.data()->udi());
275 }
276
277 if (old_chargeState != m_chargeState) {
278 Q_EMIT chargeStateChanged(newState: m_chargeState, udi: m_device.data()->udi());
279 }
280
281 if (old_timeToEmpty != m_timeToEmpty) {
282 Q_EMIT timeToEmptyChanged(time: m_timeToEmpty, udi: m_device.data()->udi());
283 }
284
285 if (old_timeToFull != m_timeToFull) {
286 Q_EMIT timeToFullChanged(time: m_timeToFull, udi: m_device.data()->udi());
287 }
288
289 if (old_energy != m_energy) {
290 Q_EMIT energyChanged(energy: m_energy, udi: m_device.data()->udi());
291 }
292
293 if (old_energyFull != m_energyFull) {
294 Q_EMIT energyFullChanged(energyFull: m_energyFull, udi: m_device.data()->udi());
295 }
296
297 if (old_energyFullDesign != m_energyFullDesign) {
298 Q_EMIT energyFullChanged(energyFull: m_energyFullDesign, udi: m_device.data()->udi());
299 }
300
301 if (old_energyRate != m_energyRate) {
302 Q_EMIT energyRateChanged(energyRate: m_energyRate, udi: m_device.data()->udi());
303 }
304
305 if (old_voltage != m_voltage) {
306 Q_EMIT voltageChanged(voltage: m_voltage, udi: m_device.data()->udi());
307 }
308
309 if (old_temperature != m_temperature) {
310 Q_EMIT temperatureChanged(temperature: m_temperature, udi: m_device.data()->udi());
311 }
312
313 if (old_timeToFull != m_timeToFull || old_timeToEmpty != m_timeToEmpty) {
314 Q_EMIT remainingTimeChanged(time: remainingTime(), udi: m_device.data()->udi());
315 }
316 }
317}
318
319void Battery::updateCache()
320{
321 m_isPresent = isPresent();
322 m_chargePercent = chargePercent();
323 m_capacity = capacity();
324 m_cycleCount = cycleCount();
325 m_isPowerSupply = isPowerSupply();
326 m_chargeState = chargeState();
327 m_timeToEmpty = timeToEmpty();
328 m_timeToFull = timeToFull();
329 m_energy = energy();
330 m_energyFull = energyFull();
331 m_energyFullDesign = energyFullDesign();
332 m_energyRate = energyRate();
333 m_voltage = voltage();
334 m_temperature = temperature();
335}
336
337#include "moc_upowerbattery.cpp"
338

source code of solid/src/solid/devices/backends/upower/upowerbattery.cpp