1212
1313namespace {
1414
15+ constexpr qint64 kMinimumUsageSampleMs = 650 ;
16+
1517QString readFileText (const QString &path) {
1618 QFile file (path);
1719 if (!file.open (QIODevice::ReadOnly | QIODevice::Text)) {
@@ -125,19 +127,41 @@ int readCpuTemperatureFromHwmon() {
125127 return readFirstValidTemperature (fallbackPaths);
126128}
127129
128- int readCpuTemperatureC () {
129- const int thermalZoneTemperature = readCpuTemperatureFromThermalZones ();
130- if (thermalZoneTemperature > 0 ) {
131- return thermalZoneTemperature;
130+ int parseTemperatureFromPlainText (const QString &text) {
131+ static const QRegularExpression numberPattern (
132+ QStringLiteral (R"( ([+-]?\d+(?:\.\d+)?))" ));
133+ const auto match = numberPattern.match (text);
134+ if (!match.hasMatch ()) {
135+ return 0 ;
132136 }
133137
134- const int hwmonTemperature = readCpuTemperatureFromHwmon () ;
135- if (hwmonTemperature > 0 ) {
136- return hwmonTemperature ;
137- }
138+ bool ok = false ;
139+ const double value = match. captured ( 1 ). toDouble (&ok);
140+ return ok && value > 0.0 ? static_cast < int >(value) : 0 ;
141+ }
138142
143+ int readCpuTemperatureFromSensors () {
139144 CommandRunner runner;
140- const auto result = runner.run (QStringLiteral (" sensors" ));
145+ auto result = runner.run (QStringLiteral (" sensors" ), {QStringLiteral (" -u" )});
146+ if (result.success ()) {
147+ static const QRegularExpression inputPattern (
148+ QStringLiteral (R"( \btemp\d+_input:\s*([+-]?\d+(?:\.\d+)?))" ));
149+ const QStringList lines = result.stdout .split (QLatin1Char (' \n ' ));
150+ for (const QString &line : lines) {
151+ const auto match = inputPattern.match (line.trimmed ());
152+ if (!match.hasMatch ()) {
153+ continue ;
154+ }
155+
156+ bool ok = false ;
157+ const double value = match.captured (1 ).toDouble (&ok);
158+ if (ok && value > 0.0 ) {
159+ return static_cast <int >(value);
160+ }
161+ }
162+ }
163+
164+ result = runner.run (QStringLiteral (" sensors" ));
141165 if (!result.success ()) {
142166 return 0 ;
143167 }
@@ -175,13 +199,51 @@ int readCpuTemperatureC() {
175199 return 0 ;
176200}
177201
202+ int readCpuTemperatureFromAcpi () {
203+ CommandRunner runner;
204+ const auto result = runner.run (QStringLiteral (" acpi" ), {QStringLiteral (" -t" )});
205+ return result.success () ? parseTemperatureFromPlainText (result.stdout ) : 0 ;
206+ }
207+
208+ int readCpuTemperatureFromVcgencmd () {
209+ CommandRunner runner;
210+ const auto result =
211+ runner.run (QStringLiteral (" vcgencmd" ), {QStringLiteral (" measure_temp" )});
212+ return result.success () ? parseTemperatureFromPlainText (result.stdout ) : 0 ;
213+ }
214+
215+ int readCpuTemperatureC () {
216+ const int thermalZoneTemperature = readCpuTemperatureFromThermalZones ();
217+ if (thermalZoneTemperature > 0 ) {
218+ return thermalZoneTemperature;
219+ }
220+
221+ const int hwmonTemperature = readCpuTemperatureFromHwmon ();
222+ if (hwmonTemperature > 0 ) {
223+ return hwmonTemperature;
224+ }
225+
226+ const int sensorsTemperature = readCpuTemperatureFromSensors ();
227+ if (sensorsTemperature > 0 ) {
228+ return sensorsTemperature;
229+ }
230+
231+ const int acpiTemperature = readCpuTemperatureFromAcpi ();
232+ if (acpiTemperature > 0 ) {
233+ return acpiTemperature;
234+ }
235+
236+ return readCpuTemperatureFromVcgencmd ();
237+ }
238+
178239} // namespace
179240
180241CpuMonitor::CpuMonitor (QObject *parent) : QObject(parent) {
181242 m_timer.setInterval (1000 );
182243 m_timer.setTimerType (Qt::VeryCoarseTimer);
183244 connect (&m_timer, &QTimer::timeout, this , &CpuMonitor::refresh);
184245
246+ m_sampleTimer.start ();
185247 start ();
186248 refresh ();
187249}
@@ -190,6 +252,8 @@ double CpuMonitor::usagePercent() const { return m_usagePercent; }
190252
191253int CpuMonitor::temperatureC () const { return m_temperatureC; }
192254
255+ QString CpuMonitor::statusMessage () const { return m_statusMessage; }
256+
193257bool CpuMonitor::available () const { return m_available; }
194258
195259bool CpuMonitor::running () const { return m_timer.isActive (); }
@@ -242,8 +306,11 @@ void CpuMonitor::refresh() {
242306 const quint64 idleAll = idle + iowait;
243307 const quint64 nonIdle = user + nice + system + irq + softirq + steal;
244308 const quint64 total = idleAll + nonIdle;
309+ const qint64 elapsedMs =
310+ m_sampleTimer.isValid () ? m_sampleTimer.elapsed () : kMinimumUsageSampleMs ;
245311
246- if (m_prevTotal > 0 && total >= m_prevTotal && idleAll >= m_prevIdle) {
312+ if (m_prevTotal > 0 && total >= m_prevTotal && idleAll >= m_prevIdle &&
313+ elapsedMs >= kMinimumUsageSampleMs ) {
247314 const quint64 totalDelta = total - m_prevTotal;
248315 const quint64 idleDelta = idleAll - m_prevIdle;
249316
@@ -255,10 +322,17 @@ void CpuMonitor::refresh() {
255322 }
256323 }
257324
258- m_prevTotal = total;
259- m_prevIdle = idleAll;
325+ if (m_prevTotal == 0 || elapsedMs >= kMinimumUsageSampleMs ) {
326+ m_prevTotal = total;
327+ m_prevIdle = idleAll;
328+ m_sampleTimer.restart ();
329+ }
260330
261- setTemperatureC (readCpuTemperatureC ());
331+ const int temperatureC = readCpuTemperatureC ();
332+ setTemperatureC (temperatureC);
333+ setStatusMessage (temperatureC > 0
334+ ? tr (" CPU temperature is being read from system sensors." )
335+ : tr (" CPU temperature sensor is not exposed by the kernel." ));
262336 setAvailable (true );
263337}
264338
@@ -307,6 +381,15 @@ void CpuMonitor::setTemperatureC(int value) {
307381 emit temperatureCChanged ();
308382}
309383
384+ void CpuMonitor::setStatusMessage (const QString &value) {
385+ if (m_statusMessage == value) {
386+ return ;
387+ }
388+
389+ m_statusMessage = value;
390+ emit statusMessageChanged ();
391+ }
392+
310393void CpuMonitor::setAvailable (bool value) {
311394 if (m_available == value) {
312395 return ;
0 commit comments