Hi!
I found a solution from de default widget on a couple post on reddit and this forum, it make some changes on the code of 2 files.
main.qml
``/*
- Copyright 2015 Martin Kotelnik clearmartin@seznam.cz
-
- This program 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 2 of
- the License, or (at your option) any later version.
-
- This program 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 this program. If not, see <http: //www.gnu.org/licenses/>.
*/
import QtQuick 2.2
import QtQuick.Layouts 1.1
import QtGraphicalEffects 1.0
import org.kde.plasma.plasmoid 2.0
import org.kde.plasma.core 2.0 as PlasmaCore
import "../code/model-utils.js" as ModelUtils
import "../code/config-utils.js" as ConfigUtils
Item {
id: main
anchors.fill: parent
property bool vertical: (plasmoid.formFactor == PlasmaCore.Types.Vertical)
property bool planar: (plasmoid.formFactor == PlasmaCore.Types.Planar)
property bool initialized: false
// configuration
property int temperatureUnit: plasmoid.configuration.temperatureUnit
property string configuredResources: plasmoid.configuration.resources
property int baseWarningTemperature: plasmoid.configuration.warningTemperature
property int baseMeltdownTemperature: plasmoid.configuration.meltdownTemperature
property int updateInterval: 1000 * plasmoid.configuration.updateInterval
property int itemMargin: 5
property double itemWidth: 0
property double itemHeight: 0
property color warningColor: Qt.tint(theme.textColor, '#60FF0000')
property var textFontFamily: theme.defaultFont.family
Plasmoid.preferredRepresentation: Plasmoid.fullRepresentation
property double aliasFontSize: itemHeight * plasmoid.configuration.aliasFontSize * 0.01
property double temperatureFontSize: itemHeight * plasmoid.configuration.temperatureFontSize * 0.01
property double iconFontSize: itemHeight * plasmoid.configuration.iconFontSize * 0.01
property double temperatureRightMargin: itemHeight * plasmoid.configuration.temperatureRightMargin * 0.01
property double iconBottomMargin: itemHeight * plasmoid.configuration.iconBottomMargin * 0.01
property bool enableLabelDropShadow: plasmoid.configuration.enableLabelDropShadow
property var systemmonitorAvailableSources
property var systemmonitorSourcesToAdd
property int numberOfParts: temperatureModel.count
property double parentWidth: parent !== null ? parent.width : 0
property double parentHeight: parent !== null ? parent.height : 0
property double widgetWidth: 0
property double widgetHeight: 0
Layout.preferredWidth: widgetWidth
Layout.preferredHeight: widgetHeight
property bool debugLogging: false
function dbgprint(msg) {
if (!debugLogging) {
return
}
print('[thermalMonitor] ' + msg)
}
onParentWidthChanged: setWidgetSize()
onParentHeightChanged: setWidgetSize()
onNumberOfPartsChanged: setWidgetSize()
function setWidgetSize() {
if (!parentHeight) {
return
}
var orientationVertical = false
if (planar) {
var contentItemWidth = parentHeight
var contentWidth = numberOfParts * contentItemWidth + (numberOfParts-1) * itemMargin
var restrictToWidth = contentWidth / parentWidth > 1
itemWidth = restrictToWidth ? (parentWidth + itemMargin) / numberOfParts - itemMargin : contentItemWidth
} else if (vertical) {
orientationVertical = true
itemWidth = parentWidth
} else {
itemWidth = parentHeight
}
itemHeight = itemWidth
widgetWidth = orientationVertical ? itemWidth : numberOfParts * itemWidth + (numberOfParts-1) * itemMargin
widgetHeight = orientationVertical ? numberOfParts * itemHeight + (numberOfParts-1) * itemMargin : itemHeight
}
FontLoader {
source: '../fonts/fontawesome-webfont-4.3.0.ttf'
}
Image {
id: noResourceIcon;
anchors.centerIn: parent
visible: temperatureModel.count === 0
height: itemHeight
width: height
source: '../images/thermal-monitor.svg'
}
ListView {
id: listView
anchors.centerIn: parent
width: widgetWidth
height: widgetHeight
orientation: !planar && vertical ? ListView.Vertical : ListView.Horizontal
spacing: itemMargin
model: temperatureModel
delegate: TemperatureItem {}
}
/*
*
* One object has these properties: temperature, alias and other
*
*/
ListModel {
id: temperatureModel
}
Component.onCompleted: {
plasmoid.setAction('reloadSources', i18n('Reload Temperature Sources'), 'system-reboot');
reloadAllSources()
setWidgetSize()
}
onBaseWarningTemperatureChanged: {
tryReloadSources()
}
onBaseMeltdownTemperatureChanged: {
tryReloadSources()
}
onConfiguredResourcesChanged: {
dbgprint('configured resources changed')
tryReloadSources()
}
function tryReloadSources() {
if (!initialized) {
dbgprint('applet not initialized -> no reloading sources')
return
}
reloadAllSources()
}
function getSystemmonitorAvailableSources() {
if (!systemmonitorAvailableSources) {
systemmonitorAvailableSources = systemmonitorDS.sources
}
return systemmonitorAvailableSources
}
function action_reloadSources() {
reloadAllSources()
}
function reloadAllSources() {
dbgprint('reloading all sources...')
var resources = ConfigUtils.getResourcesObjectArray()
temperatureModel.clear()
if (!systemmonitorAvailableSources) {
systemmonitorAvailableSources = []
}
if (!systemmonitorSourcesToAdd) {
systemmonitorSourcesToAdd = []
}
if (systemmonitorDS.connectedSources === undefined) {
systemmonitorDS.connectedSources = []
}
if (udisksDS.connectedSources === undefined) {
udisksDS.connectedSources = []
}
if (nvidiaDS.connectedSources === undefined) {
nvidiaDS.connectedSources = []
}
if (atiDS.connectedSources === undefined) {
atiDS.connectedSources = []
}
systemmonitorSourcesToAdd.length = 0
systemmonitorDS.connectedSources.length = 0
udisksDS.connectedSources.length = 0
udisksDS.cmdSourceBySourceName = {}
nvidiaDS.connectedSources.length = 0
atiDS.connectedSources.length = 0
ModelUtils.initModels(resources, temperatureModel)
for (var i = 0; i < temperatureModel.count; i++) {
var tempObj = temperatureModel.get(i)
var source = tempObj.sourceName
if (source === 'group-of-sources') {
dbgprint('adding group: ' + tempObj.alias)
for (var childSource in tempObj.childSourceObjects) {
dbgprint('adding source (for group): ' + childSource)
addSourceToDs(childSource)
}
} else {
addSourceToDs(source)
}
}
ModelUtils.rebuildModelIndexByKey(temperatureModel)
initialized = true
dbgprint('reloadAllSources() DONE')
}
function addSourceToDs(source) {
if (source.indexOf('udisks/') === 0) {
var diskLabel = source.substring('udisks/'.length)
var cmdSource = ModelUtils.getUdisksTemperatureCmd(diskLabel)
udisksDS.cmdSourceBySourceName[cmdSource] = source
dbgprint('adding source to udisksDS: ' + cmdSource)
addToSourcesOfDatasource(udisksDS, cmdSource)
} else if (source.indexOf('nvidia-') === 0 && nvidiaDS.connectedSources.length === 0) {
dbgprint('adding source to nvidiaDS')
addToSourcesOfDatasource(nvidiaDS, nvidiaDS.nvidiaSource)
} else if (source.indexOf('aticonfig') === 0 && atiDS.connectedSources.length === 0) {
dbgprint('adding source to atiDS')
addToSourcesOfDatasource(atiDS, atiDS.atiSource)
} else {
dbgprint('adding source to systemmonitorDS: ' + source)
if (getSystemmonitorAvailableSources().indexOf(source) > -1) {
dbgprint('adding to connected')
addToSourcesOfDatasource(systemmonitorDS, source)
} else {
dbgprint('adding to sta')
systemmonitorSourcesToAdd.push(source)
}
}
}
function addToSourcesOfDatasource(datasource, sourceName) {
if (datasource.connectedSources.indexOf(sourceName) > -1) {
// already added
dbgprint('source already added: ' + sourceName)
return
}
datasource.connectedSources.push(sourceName)
}
PlasmaCore.DataSource {
id: systemmonitorDS
engine: 'systemmonitor'
property string lmSensorsStart: 'lmsensors/'
property string acpiStart: 'acpi/Thermal_Zone/'
onSourceAdded: {
if (source.indexOf(lmSensorsStart) === 0 || source.indexOf(acpiStart) === 0) {
systemmonitorAvailableSources.push(source)
var staIndex = systemmonitorSourcesToAdd.indexOf(source)
if (staIndex > -1) {
addToSourcesOfDatasource(systemmonitorDS, source)
systemmonitorSourcesToAdd.splice(staIndex, 1)
}
}
}
onNewData: {
var temperature = 0
if (data.value === undefined) {
dbgprint('data for source ' + sourceName + ' not yet available')
} else {
temperature = parseFloat(data.value)
}
ModelUtils.updateTemperatureModel(temperatureModel, sourceName, temperature)
}
interval: updateInterval
}
PlasmaCore.DataSource {
id: udisksDS
engine: 'executable'
property var cmdSourceBySourceName
onNewData: {
dbgprint('udisks new data - valid: ' + valid + ', stdout: ' + data.stdout)
var temperature = 0
if (data['exit code'] > 0) {
dbgprint('new data error: ' + data.stderr)
} else {
temperature = ModelUtils.getCelsiaFromUdisksStdout(data.stdout)
}
ModelUtils.updateTemperatureModel(temperatureModel, cmdSourceBySourceName[sourceName], temperature)
}
interval: updateInterval
}
PlasmaCore.DataSource {
id: nvidiaDS
engine: 'executable'
property string nvidiaSource: 'nvidia-smi --query-gpu=temperature.gpu --format=csv,noheader'
onNewData: {
var temperature = 0
if (data['exit code'] > 0) {
dbgprint('new data error: ' + data.stderr)
} else {
temperature = parseFloat(data.stdout)
}
ModelUtils.updateTemperatureModel(temperatureModel, 'nvidia-smi', temperature)
}
interval: updateInterval
}
PlasmaCore.DataSource {
id: atiDS
engine: 'executable'
property string atiSource: 'aticonfig --od-gettemperature | tail -1 | cut -c 43-44'
onNewData: {
var temperature = 0
if (data['exit code'] > 0) {
dbgprint('new data error: ' + data.stderr)
} else {
temperature = parseFloat(data.stdout)
}
ModelUtils.updateTemperatureModel(temperatureModel, 'aticonfig', temperature)
}
interval: updateInterval
}
Timer {
interval: updateInterval
repeat: true
running: true
onTriggered: {
ModelUtils.computeVirtuals(temperatureModel)
}
}
}
ConfigTemperatures.qml
type or paste code here
import QtQuick 2.2
import QtQuick.Controls 1.3
import QtQuick.Dialogs 1.2
import QtQuick.Layouts 1.1
import org.kde.plasma.core 2.0 as PlasmaCore
import "../../code/config-utils.js" as ConfigUtils
import "../../code/model-utils.js" as ModelUtils
Item {
id: resourcesConfigPage
property double tableWidth: parent.width
property string cfg_resources
property alias cfg_warningTemperature: warningTemperatureSpinBox.value
property alias cfg_meltdownTemperature: meltdownTemperatureSpinBox.value
property var preparedSystemMonitorSources: []
ListModel {
id: resourcesModel
}
ListModel {
id: comboboxModel
}
ListModel {
id: checkboxesSourcesModel
}
Component.onCompleted: {
systemmonitorDS.sources.forEach(function (source) {
if ((source.indexOf('lmsensors/') === 0 || source.indexOf('acpi/Thermal_Zone/') === 0)
&& !source.match(/\/fan[0-9]*$/) ) {
comboboxModel.append({
text: source,
val: source
})
print('source to combo: ' + source)
}
})
var resources = ConfigUtils.getResourcesObjectArray()
resources.forEach(function (resourceObj) {
resourcesModel.append(resourceObj)
})
}
function reloadComboboxModel(temperatureObj) {
temperatureObj = temperatureObj || {}
var childSourceObjects = temperatureObj.childSourceObjects || {}
var childSourceObjectsEmpty = !temperatureObj.childSourceObjects
checkboxesSourcesModel.clear()
sourceCombo.currentIndex = 0
print('sourceName to select: ' + temperatureObj.sourceName)
addResourceDialog.sourceTypeSwitch = temperatureObj.sourceName === 'group-of-sources' ? 1 : 0
addResourceDialog.setVirtualSelected()
addResourceDialog.groupSources.length = 0
for (var i = 0; i < comboboxModel.count; i++) {
var source = comboboxModel.get(i).val
if (source === temperatureObj.sourceName) {
sourceCombo.currentIndex = i
}
var checkboxChecked = childSourceObjectsEmpty || (source in childSourceObjects)
checkboxesSourcesModel.append({
text: source,
val: source,
checkboxChecked: checkboxChecked
})
if (checkboxChecked) {
addResourceDialog.groupSources.push(source)
}
}
}
function resourcesModelChanged() {
var newResourcesArray = []
for (var i = 0; i < resourcesModel.count; i++) {
var obj = resourcesModel.get(i)
newResourcesArray.push({
sourceName: obj.sourceName,
alias: obj.alias,
overrideLimitTemperatures: obj.overrideLimitTemperatures,
warningTemperature: obj.warningTemperature,
meltdownTemperature: obj.meltdownTemperature,
virtual: obj.virtual,
childSourceObjects: obj.childSourceObjects
})
}
cfg_resources = JSON.stringify(newResourcesArray)
print('resources: ' + cfg_resources)
}
function fillAddResourceDialogAndOpen(temperatureObj, editResourceIndex) {
// set dialog title
addResourceDialog.addResource = temperatureObj === null
addResourceDialog.editResourceIndex = editResourceIndex
temperatureObj = temperatureObj || {
alias: '',
overrideLimitTemperatures: false,
meltdownTemperature: 90,
warningTemperature: 70
}
// set combobox
reloadComboboxModel(temperatureObj)
// alias
aliasTextfield.text = temperatureObj.alias
showAlias.checked = !!temperatureObj.alias
// temperature overrides
overrideLimitTemperatures.checked = temperatureObj.overrideLimitTemperatures
warningTemperatureItem.value = temperatureObj.warningTemperature
meltdownTemperatureItem.value = temperatureObj.meltdownTemperature
// open dialog
addResourceDialog.open()
}
Dialog {
id: addResourceDialog
property bool addResource: true
property int editResourceIndex: -1
title: addResource ? i18n('Add Resource') : i18n('Edit Resource')
width: tableWidth
property int tableIndex: 0
property double fieldHeight: addResourceDialog.height / 5 - 3
property bool virtualSelected: true
standardButtons: StandardButton.Ok | StandardButton.Cancel
property int sourceTypeSwitch: 0
property var groupSources: []
ExclusiveGroup {
id: sourceTypeGroup
}
onSourceTypeSwitchChanged: {
switch (sourceTypeSwitch) {
case 0:
sourceTypeGroup.current = singleSourceTypeRadio;
break;
case 1:
sourceTypeGroup.current = multipleSourceTypeRadio;
break;
default:
}
setVirtualSelected()
}
function setVirtualSelected() {
virtualSelected = sourceTypeSwitch === 1
print('SET VIRTUAL SELECTED: ' + virtualSelected)
}
onAccepted: {
if (!showAlias.checked) {
aliasTextfield.text = ''
} else if (!aliasTextfield.text) {
aliasTextfield.text = '<UNKNOWN>'
}
var childSourceObjects = {}
groupSources.forEach(function (groupSource) {
print ('adding source to group: ' + groupSource)
childSourceObjects[groupSource] = {
temperature: 0
}
})
var newObject = {
sourceName: virtualSelected ? 'group-of-sources' : comboboxModel.get(sourceCombo.currentIndex).val,
alias: aliasTextfield.text,
overrideLimitTemperatures: overrideLimitTemperatures.checked,
warningTemperature: warningTemperatureItem.value,
meltdownTemperature: meltdownTemperatureItem.value,
virtual: virtualSelected,
childSourceObjects: childSourceObjects
}
if (addResourceDialog.addResource) {
resourcesModel.append(newObject)
} else {
resourcesModel.set(addResourceDialog.editResourceIndex, newObject)
}
resourcesModelChanged()
addResourceDialog.close()
}
GridLayout {
columns: 2
RadioButton {
id: singleSourceTypeRadio
exclusiveGroup: sourceTypeGroup
text: i18n("Source")
onCheckedChanged: {
if (checked) {
addResourceDialog.sourceTypeSwitch = 0
}
addResourceDialog.setVirtualSelected()
}
checked: true
}
ComboBox {
id: sourceCombo
Layout.preferredWidth: tableWidth/2
model: comboboxModel
enabled: !addResourceDialog.virtualSelected
}
RadioButton {
id: multipleSourceTypeRadio
exclusiveGroup: sourceTypeGroup
text: i18n("Group of sources")
onCheckedChanged: {
if (checked) {
addResourceDialog.sourceTypeSwitch = 1
}
addResourceDialog.setVirtualSelected()
}
Layout.alignment: Qt.AlignTop
}
ListView {
id: checkboxesSourcesListView
model: checkboxesSourcesModel
delegate: CheckBox {
text: val
checked: checkboxChecked
onCheckedChanged: {
if (checked) {
if (addResourceDialog.groupSources.indexOf(val) === -1) {
addResourceDialog.groupSources.push(val)
}
} else {
var idx = addResourceDialog.groupSources.indexOf(val)
if (idx !== -1) {
addResourceDialog.groupSources.splice(idx, 1)
}
}
}
}
enabled: addResourceDialog.virtualSelected
Layout.preferredWidth: tableWidth/2
Layout.preferredHeight: contentHeight
}
Item {
Layout.columnSpan: 2
width: 2
height: 5
}
Label {
text: i18n("NOTE: Group of sources shows the highest temperature of chosen sources.")
Layout.columnSpan: 2
enabled: addResourceDialog.virtualSelected
}
Item {
Layout.columnSpan: 2
width: 2
height: 10
}
CheckBox {
id: showAlias
text: i18n("Show alias:")
checked: true
Layout.alignment: Qt.AlignRight
}
TextField {
id: aliasTextfield
Layout.preferredWidth: tableWidth/2
enabled: showAlias.checked
}
Item {
Layout.columnSpan: 2
width: 2
height: 10
}
CheckBox {
id: overrideLimitTemperatures
text: i18n("Override limit temperatures")
Layout.columnSpan: 2
checked: false
}
Label {
text: i18n('Warning temperature [°C]:')
Layout.alignment: Qt.AlignRight
}
SpinBox {
id: warningTemperatureItem
stepSize: 10
minimumValue: 10
enabled: overrideLimitTemperatures.checked
}
Label {
text: i18n('Meltdown temperature [°C]:')
Layout.alignment: Qt.AlignRight
}
SpinBox {
id: meltdownTemperatureItem
stepSize: 10
minimumValue: 10
enabled: overrideLimitTemperatures.checked
}
}
}
GridLayout {
columns: 2
Label {
text: i18n('Plasmoid version: ') + '1.2.8'
Layout.alignment: Qt.AlignRight
Layout.columnSpan: 2
}
Label {
text: i18n('Resources')
font.bold: true
Layout.alignment: Qt.AlignLeft
}
Item {
width: 2
height: 2
}
TableView {
headerVisible: true
Label {
text: i18n('Add resources by clicking "+" button.')
anchors.centerIn: parent
visible: resourcesModel.count === 0
}
TableViewColumn {
role: 'sourceName'
title: i18n('Source')
width: tableWidth * 0.6
delegate: MouseArea {
anchors.fill: parent
Label {
text: styleData.value
elide: Text.ElideRight
anchors.left: parent.left
anchors.leftMargin: 5
anchors.right: parent.right
anchors.rightMargin: 5
}
cursorShape: Qt.PointingHandCursor
onClicked: {
fillAddResourceDialogAndOpen(resourcesModel.get(styleData.row), styleData.row)
}
}
}
TableViewColumn {
role: 'alias'
title: i18n('Alias')
width: tableWidth * 0.15
delegate: MouseArea {
anchors.fill: parent
Label {
text: styleData.value
elide: Text.ElideRight
anchors.left: parent.left
anchors.leftMargin: 5
anchors.right: parent.right
anchors.rightMargin: 5
}
cursorShape: Qt.PointingHandCursor
onClicked: {
fillAddResourceDialogAndOpen(resourcesModel.get(styleData.row), styleData.row)
}
}
}
TableViewColumn {
title: i18n('Action')
width: tableWidth * 0.25 - 4
delegate: Item {
GridLayout {
height: parent.height
columns: 3
rowSpacing: 0
Button {
iconName: 'go-up'
Layout.fillHeight: true
onClicked: {
resourcesModel.move(styleData.row, styleData.row - 1, 1)
resourcesModelChanged()
}
enabled: styleData.row > 0
}
Button {
iconName: 'go-down'
Layout.fillHeight: true
onClicked: {
resourcesModel.move(styleData.row, styleData.row + 1, 1)
resourcesModelChanged()
}
enabled: styleData.row < resourcesModel.count - 1
}
Button {
iconName: 'list-remove'
Layout.fillHeight: true
onClicked: {
resourcesModel.remove(styleData.row)
resourcesModelChanged()
}
}
}
}
}
model: resourcesModel
Layout.preferredHeight: 150
Layout.preferredWidth: tableWidth
Layout.columnSpan: 2
}
Button {
id: buttonAddResource
iconName: 'list-add'
Layout.preferredWidth: 100
Layout.columnSpan: 2
onClicked: {
fillAddResourceDialogAndOpen(null, -1)
}
}
Item {
width: 2
height: 20
Layout.columnSpan: 2
}
Label {
text: i18n('Notifications')
font.bold: true
Layout.alignment: Qt.AlignLeft
}
Item {
width: 2
height: 2
}
Label {
text: i18n('Warning temperature [°C]:')
Layout.alignment: Qt.AlignRight
}
SpinBox {
id: warningTemperatureSpinBox
stepSize: 1
minimumValue: 10
maximumValue: 200
}
Label {
text: i18n('Meltdown temperature [°C]:')
Layout.alignment: Qt.AlignRight
}
SpinBox {
id: meltdownTemperatureSpinBox
stepSize: 1
minimumValue: 10
maximumValue: 200
}
}
PlasmaCore.DataSource {
id: systemmonitorDS
engine: 'systemmonitor'
}
PlasmaCore.DataSource {
id: udisksDS
engine: 'executable'
connectedSources: [ ModelUtils.UDISKS_DEVICES_CMD ]
property bool prepared: false
onNewData: {
if (!prepared)
{
//connectedSources.length = 0
if (data['exit code'] > 0) {
print('New data incomming. Source: ' + sourceName + ', ERROR: ' + data.stderr);
return
}
print('New data incomming. Source: ' + sourceName + ', data: ' + data.stdout);
var pathsToCheck = ModelUtils.parseUdisksPaths(data.stdout)
pathsToCheck.forEach(function (pathObj) {
var cmd = ModelUtils.UDISKS_VIRTUAL_PATH_PREFIX + pathObj.name
comboboxModel.append({
text: cmd,
val: cmd
})
})
prepared = true
}
}
//interval: 500
}
PlasmaCore.DataSource {
id: nvidiaDS
engine: 'executable'
connectedSources: [ 'nvidia-smi --query-gpu=temperature.gpu --format=csv,noheader' ]
property bool prepared: false
onNewData: {
if (!prepared)
{
//nvidiaDS.connectedSources.length = 0
if (data['exit code'] > 0) {
prepared = true
return
}
comboboxModel.append({
text: 'nvidia-smi',
val: 'nvidia-smi'
})
prepared = true
}
}
//interval: 500
}
PlasmaCore.DataSource {
id: atiDS
engine: 'executable'
connectedSources: [ 'aticonfig --od-gettemperature' ]
property bool prepared: false
onNewData: {
if (!prepared)
{
//atiDS.connectedSources.length = 0
if (data['exit code'] > 0) {
prepared = true
return
}
comboboxModel.append({
text: 'aticonfig',
val: 'aticonfig'
})
prepared = true
}
}
//interval: 500
}
}
type or paste code here