Search code examples
python-3.xpyqt5raspberry-pi3temperatureqlabel

Pyqt5 - how to update label with temperature (ds18b20)


Im trying to build a temperature monitor using pyqt5 on a raspberry pi 3 with ds18b20 sensors attached. I am pretty new to python and pyqt5.

The Gui file (frameless.py) was developed with QT 4 designer. The Gui should serve as a basic example for a more enviromental sensors (e.g pH EC etc.) to be implemented. The actual code (runframeless.py) is shown below.

I am well aware that is is best to use threads (or Multithreading) if more senosor data are to be read at the same time, but currently I am stuck in a pretty simple problem.

Problem: The temperature is shown in the textlabel, but the temperature value in def read_temp(self) is not updated.

Question: Can anyone explain why it is not updated and help me getting the code right so that the temperature value shown in the gui is changed when the temperature acually changes?

runframeless.py

# -*- coding: utf-8 -*-
# file: runframeless.py)
#-create a skeleton class(es) for Raspberry Pi GUI-

# need this
import sys
import time
import datetime
import os
import glob
#----This gets the Qt stuff------------------------
from PyQt5 import QtGui
from PyQt5 import QtCore
from PyQt5 import QtWidgets

from PyQt5.QtCore import Qt

from PyQt5.QtWidgets import QMainWindow
from PyQt5.QtWidgets import QApplication
from PyQt5.QtWidgets import QLabel


# Import QtCreator/qtdesigner file
import frameless

os.system('modprobe w1-gpio')
os.system('modprobe w1-therm')

base_dir = '/sys/bus/w1/devices/'
device_folder = glob.glob(base_dir + '10*')[0]
device_file = device_folder + '/w1_slave'

#-------------------------------------------------
#----class(es) for our Raspberry Pi GUI-----------
#-------------------------------------------------

class MainWindow(QMainWindow, frameless.Ui_MainWindow): 
    def __init__(self):
        super(self.__class__, self).__init__()
        self.setupUi(self) # gets defined in the UI file

        self.label.setText(str(self.read_temp()))


        self.timer = QtCore.QTimer(self)
        self.timer.setInterval(1000)
        self.timer.timeout.connect(self.read_temp)
        self.timer.start()    

    def read_temp(self):
        f = open(device_file, 'r')
        lines = f.readlines()
        f.close()
        time.sleep(.1)
        while lines[0].strip()[-3:] != 'YES':
            time.sleep(.1)
            #lines = self.read_temp()
        equals_pos = lines[1].find('t=')
        if equals_pos != -1:
            temp_string = lines[1][equals_pos+2:]
            temp_c = float(temp_string) / 1000.0
            return temp_c


if __name__ == "__main__": 
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()

    sys.exit(app.exec_())

file: frameless.py

# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'frameless.ui'
#
# Created: Tue Feb 27 17:31:49 2018
#      by: PyQt5 UI code generator 5.3.2
#
# WARNING! All changes made in this file will be lost!

from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import Qt

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        self.setWindowFlags(Qt.FramelessWindowHint) # frameless
        MainWindow.resize(800, 480)
        MainWindow.setStyleSheet("background:rgb(0, 0, 0);")
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setStyleSheet("")
        self.centralwidget.setObjectName("centralwidget")
        self.pushButton = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton.setGeometry(QtCore.QRect(660, 430, 101, 31))
        self.pushButton.setStyleSheet("background: rgb(255, 255, 255) ")
        self.pushButton.setObjectName("pushButton")
        self.widget = QtWidgets.QWidget(self.centralwidget)
        self.widget.setGeometry(QtCore.QRect(10, 170, 751, 41))
        self.widget.setObjectName("widget")
        self.horizontalLayout = QtWidgets.QHBoxLayout(self.widget)
        self.horizontalLayout.setContentsMargins(0, 0, 0, 0)
        self.horizontalLayout.setObjectName("horizontalLayout")
        self.label_2 = QtWidgets.QLabel(self.widget)
        self.label_2.setStyleSheet("background: rgb(255, 255, 255) ")
        self.label_2.setObjectName("label_2")
        self.horizontalLayout.addWidget(self.label_2)
        self.label = QtWidgets.QLabel(self.widget)
        self.label.setStyleSheet("background: rgb(255, 255, 255) ")
        self.label.setObjectName("label")
        self.horizontalLayout.addWidget(self.label)
        MainWindow.setCentralWidget(self.centralwidget)

        self.retranslateUi(MainWindow)
        self.pushButton.clicked.connect(MainWindow.close)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.pushButton.setText(_translate("MainWindow", "exit"))
        self.label_2.setText(_translate("MainWindow", "Ds18B20-sensor"))
        self.label.setText(_translate("MainWindow", "TextLabel"))


if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    MainWindow = QtWidgets.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()
    sys.exit(app.exec_())

Solution

  • When debugging code, it pays to logically step through how the program works.

    Firstly, this line self.label.setText(str(self.read_temp())) runs once as it is in the __init__ method. This calls the self.read_temp() method which returns the temperature and places it in the text box.

    Next, you create a QTimer in the __init__ method, which calls self.read_temp() every second. So when the timer triggers every second, self.read_temp is run, the temperature is read out, and returned to whatever internal code the QTimer uses to call your method.

    At this point the QTimer throws away the return value because it doesn't want it, can't use it, etc.

    As you can probably now see, the reason why it doesn't update is because you have never told it to update.

    I would suggest adding the line self.label.setText(str(temp_c)) prior to the return temp_c line in order to update the label from the code that runs every second.