8#include "SensorDataModel.h"
15#include "formatter/Formatter.h"
16#include "systemstats/SensorInfo.h"
18#include "SensorDaemonInterface_p.h"
19#include "sensors_logging.h"
21using namespace KSysGuard;
23namespace chrono = std::chrono;
33 void sensorsChanged();
34 void addSensor(
const QString &
id);
35 void removeSensor(
const QString &
id);
44 QVariantMap sensorColors;
45 QVariantMap sensorLabels;
47 bool usedByQml =
false;
48 bool componentComplete =
false;
52 std::optional<qreal> minimum;
53 std::optional<qreal> maximum;
55 std::optional<int> updateRateLimit;
64 , d(new Private(this))
66 connect(SensorDaemonInterface::instance(), &SensorDaemonInterface::sensorAdded,
this, &SensorDataModel::onSensorAdded);
67 connect(SensorDaemonInterface::instance(), &SensorDaemonInterface::sensorRemoved,
this, &SensorDataModel::onSensorRemoved);
68 connect(SensorDaemonInterface::instance(), &SensorDaemonInterface::metaDataChanged,
this, &SensorDataModel::onMetaDataChanged);
69 connect(SensorDaemonInterface::instance(), &SensorDaemonInterface::valueChanged,
this, &SensorDataModel::onValueChanged);
72 d->objects << QStringLiteral(
"");
74 setSensors(sensorIds);
77SensorDataModel::~SensorDataModel()
87 for (
int i = 0; i < e.
keyCount(); ++i) {
96 const bool check =
checkIndex(
index, CheckIndexOption::IndexIsValid | CheckIndexOption::DoNotUseParent);
102 auto info = d->sensorInfos.value(sensor);
103 auto data = d->sensorData.value(sensor);
114 return d->sensorLabels.value(sensor, info.name);
116 auto it = d->sensorLabels.constFind(sensor);
117 if (it != d->sensorLabels.constEnd()) {
120 if (info.shortName.isEmpty()) {
123 return info.shortName;
126 return info.description;
132 return info.variantType;
136 if (!d->sensorColors.empty()) {
137 return d->sensorColors.value(sensor);
142 return BackendUpdateInterval;
156 if (section < 0 || section >= d->sensors.size()) {
160 auto sensor = d->sensors.at(section);
161 auto info = d->sensorInfos.value(sensor);
166 if (info.shortName.isEmpty()) {
169 return info.shortName;
177 return info.description;
183 return info.variantType;
186 return BackendUpdateInterval;
194int SensorDataModel::rowCount(
const QModelIndex &parent)
const
200 return d->objects.count();
203int SensorDataModel::columnCount(
const QModelIndex &parent)
const
209 return d->sensorInfos.count();
214 if (d->sensors.isEmpty()) {
218 if (d->minimum.has_value()) {
219 return d->minimum.value();
222 auto result = std::min_element(d->sensorInfos.cbegin(), d->sensorInfos.cend(), [](
const SensorInfo &first,
const SensorInfo &second) {
223 return first.min < second.min;
225 if (result == d->sensorInfos.cend()) {
228 d->minimum = (*result).min;
230 return d->minimum.value();
235 if (d->sensors.isEmpty()) {
239 if (d->maximum.has_value()) {
240 return d->maximum.value();
243 auto result = std::max_element(d->sensorInfos.cbegin(), d->sensorInfos.cend(), [](
const SensorInfo &first,
const SensorInfo &second) {
244 return first.max < second.max;
246 if (result == d->sensorInfos.cend()) {
249 d->maximum = (*result).max;
251 return d->maximum.value();
256 return d->requestedSensors;
259void SensorDataModel::setSensors(
const QStringList &sensorIds)
261 if (d->requestedSensors == sensorIds) {
265 d->requestedSensors = sensorIds;
267 if (!d->usedByQml || d->componentComplete) {
279void SensorDataModel::setEnabled(
bool newEnabled)
281 if (newEnabled == d->enabled) {
285 d->enabled = newEnabled;
287 SensorDaemonInterface::instance()->subscribe(d->sensorInfos.keys());
288 SensorDaemonInterface::instance()->requestMetaData(d->sensorInfos.keys());
290 SensorDaemonInterface::instance()->unsubscribe(d->sensorInfos.keys());
298 return d->sensorColors;
301void SensorDataModel::setSensorColors(
const QVariantMap &sensorColors)
307 Q_EMIT sensorColorsChanged();
313 return d->sensorLabels;
316void SensorDataModel::setSensorLabels(
const QVariantMap &sensorLabels)
322 Q_EMIT sensorLabelsChanged();
328 return d->updateRateLimit.value_or(-1);
331void SensorDataModel::setUpdateRateLimit(
int newUpdateRateLimit)
335 if (newUpdateRateLimit <= 0) {
336 if (!d->updateRateLimit) {
340 d->updateRateLimit.reset();
342 if (d->updateRateLimit && d->updateRateLimit.value() == newUpdateRateLimit) {
346 d->updateRateLimit = newUpdateRateLimit;
348 d->lastUpdateTimes.clear();
349 Q_EMIT updateRateLimitChanged();
352void KSysGuard::SensorDataModel::resetUpdateRateLimit()
354 setUpdateRateLimit(-1);
357bool KSysGuard::SensorDataModel::isReady()
const
359 return d->sensors.size() == d->sensorInfos.size();
362void SensorDataModel::addSensor(
const QString &sensorId)
364 d->addSensor(sensorId);
367void SensorDataModel::removeSensor(
const QString &sensorId)
369 d->removeSensor(sensorId);
372int KSysGuard::SensorDataModel::column(
const QString &sensorId)
const
374 return d->sensors.indexOf(sensorId);
377void KSysGuard::SensorDataModel::classBegin()
382void KSysGuard::SensorDataModel::componentComplete()
384 d->componentComplete =
true;
388 Q_EMIT sensorsChanged();
391void SensorDataModel::Private::addSensor(
const QString &
id)
393 if (!requestedSensors.
contains(
id)) {
397 qCDebug(LIBKSYSGUARD_SENSORS) <<
"Add Sensor" << id;
400 SensorDaemonInterface::instance()->subscribe(
id);
401 SensorDaemonInterface::instance()->requestMetaData(
id);
404void SensorDataModel::Private::removeSensor(
const QString &
id)
406 const int col =
sensors.indexOf(
id);
414 sensorInfos.remove(
id);
415 sensorData.remove(
id);
417 q->endRemoveColumns();
420void SensorDataModel::onSensorAdded(
const QString &sensorId)
426 d->addSensor(sensorId);
429void SensorDataModel::onSensorRemoved(
const QString &sensorId)
435 d->removeSensor(sensorId);
438void SensorDataModel::onMetaDataChanged(
const QString &sensorId,
const SensorInfo &info)
444 auto column = d->sensors.indexOf(sensorId);
449 qCDebug(LIBKSYSGUARD_SENSORS) <<
"Received metadata change for" << sensorId;
455 if (d->sensorInfos.contains(sensorId)) {
456 d->sensorInfos[sensorId] = info;
457 Q_EMIT dataChanged(
index(0, column),
index(0, column), {
Qt::DisplayRole,
Name,
ShortName,
Description,
Unit,
Minimum,
Maximum,
Type,
FormattedValue});
458 Q_EMIT sensorMetaDataChanged();
465 while (d->sensorInfos.count() + 1 <= column && column > 0) {
470 d->sensorInfos[sensorId] = info;
471 d->sensorData[sensorId] =
QVariant{};
474 SensorDaemonInterface::instance()->requestValue(sensorId);
475 Q_EMIT sensorMetaDataChanged();
482void SensorDataModel::onValueChanged(
const QString &sensorId,
const QVariant &value)
484 const auto column = d->sensors.indexOf(sensorId);
485 if (column == -1 || !d->enabled) {
489 if (d->updateRateLimit && d->sensorData[sensorId].isValid()) {
490 auto updateRateLimit = chrono::steady_clock::duration(chrono::milliseconds(d->updateRateLimit.value()));
491 auto now = chrono::steady_clock::now();
492 if (d->lastUpdateTimes.contains(column) && now - d->lastUpdateTimes.value(column) <
updateRateLimit) {
495 d->lastUpdateTimes[column] = now;
499 d->sensorData[sensorId] = value;
503void SensorDataModel::Private::sensorsChanged()
505 q->beginResetModel();
507 SensorDaemonInterface::instance()->unsubscribe(
sensors);
512 lastUpdateTimes.clear();
516 SensorDaemonInterface::instance()->subscribe(requestedSensors);
517 SensorDaemonInterface::instance()->requestMetaData(requestedSensors);
A model representing a table of sensors.
@ Value
The value of the sensor.
@ Description
A description for the sensor.
@ Name
The name of the sensor.
@ ShortName
A shorter name for the sensor. This is equal to name if not set.
@ UpdateInterval
The time in milliseconds between each update of the sensor.
@ Color
A color of the sensor, if sensorColors is set.
@ FormattedValue
A formatted string of the value of the sensor.
@ Minimum
The minimum value this sensor can have.
@ SensorId
The backend path to the sensor.
@ Maximum
The maximum value this sensor can have.
@ Unit
The unit of the sensor.
@ Type
The QVariant::Type of the sensor.
int updateRateLimit
The minimum time between updates, in milliseconds.
qreal maximum
The maximum value of all sensors' maximum property.
QML_ELEMENTQStringList sensors
The list of sensors to watch.
bool enabled
Should this model be updated or not.
QVariantMap sensorLabels
Provides custom labels for Sensors that are used instead of the name and short name of the sensors.
qreal minimum
The minimum value of all sensors' minimum property.
QVariantMap sensorColors
Used by the model to provide data for the Color role if set.
void beginInsertColumns(const QModelIndex &parent, int first, int last)
bool checkIndex(const QModelIndex &index, CheckIndexOptions options) const const
void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QList< int > &roles)
virtual QHash< int, QByteArray > roleNames() const const
virtual QModelIndex index(int row, int column, const QModelIndex &parent) const const override
iterator insert(const Key &key, const T &value)
void append(QList< T > &&value)
QObject * parent() const const
bool contains(QLatin1StringView str, Qt::CaseSensitivity cs) const const
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)