Python Tkinter using Raspberry Pi updating GUI - python

recently i have been working on Tkinter in Raspberry pi to build a GUI for home automation, and i wanted to design a validation module which says "ACTIVE" when the sensor is working and "INACTIVE" when sensor has malfunctioned.
I am able to get the validation in the GUI but its not dynamic. Every time i have to re-run the program to get the updated status of the sensors
is there a way where in i can update the Active and Inactive status without re-running the entire program?
I am taking input from GPIO pins on the raspberry pi and reading them in the program
here is the code i have worked on so far:
import RPi.GPIO as GPIO
import time
from tkinter import *
from tkinter import ttk
import tkinter.font
GPIO.setwarnings(False)
Sig1 = 7
GPIO.setmode(GPIO.BOARD)
GPIO.setup(Sig1, GPIO.IN)
out1 = 11# pin11
GPIO.setmode(GPIO.BOARD) # We are accessing GPIOs according to their physical location
GPIO.setup(out1, GPIO.OUT) # We have set our LED pin mode to output
GPIO.output(out1, GPIO.LOW)
gui = Tk()
gui.title("tkinter")
gui.config(background = "gray86")
gui.minsize(1050,620)
Font1 = tkinter.font.Font(family = 'Courier 10 Pitch', size = 20, weight = 'bold')
Font2 = tkinter.font.Font(family = 'Courier 10 Pitch', size = 18, weight = 'bold')
Font3 = tkinter.font.Font(family = 'Courier 10 Pitch', size = 9, weight = 'bold')
def func1_on():
GPIO.output(out1, GPIO.HIGH) # led on
Text1 = Label(gui,text=' ON ', font = Font2, bg = 'gray84', fg='green3', padx = 0)
Text1.grid(row=8,column=1)
def func1_off():
GPIO.output(out1, GPIO.LOW) # led off
Text2 = Label(gui,text='OFF', font = Font2, bg = 'gray84', fg='red', padx = 0)
Text2.grid(row=8,column=1)
label_2 = Label(gui,text='Sensor:', font = Font2, fg='gray40', bg = 'gray84', padx = 10, pady = 10)
label_2.grid(row=6,column=0)
if GPIO.input(Sig1) == True:
Text3 = Label(gui,textvariable=' Active ',relief = "raised", font = Font2, bg = 'gray84', fg='green3', padx = 0)
Text3.grid(row=6,column=1)
else:
Text4 = Label(gui,textvariable=' Inactive ',relief = "raised", font = Font2, bg = 'gray84', fg='red', padx = 0)
Text4.grid(row=6,column=1)
Button1 = Button(gui, text='Switch On', font = Font3, command = func1_on, bg='gray74', height = 1, width = 7)
Button1.grid(row=8,column=0)
Button2 = Button(gui, text='Switch Off', font = Font3, command = func1_off, bg='gray74', height = 1, width = 7)
Button2.grid(row=9,column=0)
gui.mainloop()
it would be greatly appreciated if someone could help me with this.

Use root.after(milliseconds, function_name) run some function periodically.
This function should check sensors, update text in labels and use root.after to run again after some time.
BTW: function_name should be without ()
Minimal example. It updates label with current time
import tkinter as tk
import time
# --- functions ---
def check():
# update text in existing labels
label['text'] = time.strftime('%H:%M:%S')
# run again after 1000ms (1s)
root.after(1000, check)
# --- main ---
root = tk.Tk()
label = tk.Label(root)
label.pack()
check() # run first time
root.mainloop()

Related

DHT22 Temp sensor causing Tkinter GUI to lag

Hi I've been trying to implement a DHT22 temperature and humidity sensor with Tkinter GUI where it updates regularly while using the GUI. This is done on a Raspberry Pi 4 using Python. However, while the numbers are updating correctly, it would cause the GUI freeze momentarily while updating the numbers. I have already tried multithreading, but it unfortunately didn't help. Is there any solution to this problem? Any help is greatly appreciated.
Here's the code:
# Import the required libraries
import RPi.GPIO as GPIO
import spidev
import time
import tkinter
from tkinter import *
import tkinter.font as tkFont
from PIL import ImageTk, Image
# import time
import smbus
import serial
import os
import argparse
import Adafruit_DHT
from threading import Thread
SENSOR = Adafruit_DHT.DHT22
# GPIO4 on the Raspberry Pi
SENSOR_PIN = 4
address = 0b01
ssPin = 8
spi = spidev.SpiDev()
spi.open(0,0)
spi.max_speed_hz = 976000
spi.mode = 0b11
#spi.bit_order = msbfirst
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
GPIO.setup(ssPin,GPIO.OUT)
GPIO.setup(22,GPIO.OUT)
GPIO.setup(26,GPIO.OUT)
GPIO.output(ssPin,GPIO.LOW)
GPIO.output(22,GPIO.HIGH)
GPIO.output(26,GPIO.HIGH)
class App:
def __init__(self, master):
def SendScaleReading(self):
S = scale.get() #retrieve value from slider
if S>0:
S+=155
print(S)
spi.xfer([address ,S]) #write data to slave address
frame = Frame(master)
frame.pack()
scale = tkinter.Scale(root,from_=0,to=100,length=700,bg='black',fg='#0000FF', highlightthickness = 0, bd = 0, command=SendScaleReading) #set parameters of slider
scale.place(relx=0.75, rely=0.05)
#scale.place(relx = 0, rely = 0) # set position of slider
fontstyle = tkFont.Font(family='Arial', size=50) #initialise font
scale['font'] = fontstyle
def PowerFn():
global powerBool
# print(ledBool)
if powerBool:
#print('went to on button')
powerBtn.config(image=On_BtnImg)
powerBtn.image = On_BtnImg
#print("on button configured")
powerLabel.config(text="POWER: ON", fg='#00FF00')
# communicating with arduino
GPIO.output(26,GPIO.LOW)
else:
#print('went to off button')
powerBtn.config(image=Off_BtnImg)
powerBtn.image = Off_BtnImg
#print("off button configured")
powerLabel.config(text="POWER: OFF", fg='#FF0000')
# communicating with arduino
GPIO.output(26,GPIO.HIGH)
powerBool = not powerBool
def DirectionFn():
global directionBool
# print(cbBool)
if directionBool:
#print('went to CbOn button')
directionBtn.config(image = On_BtnImg)
directionBtn.image = On_BtnImg
#print("CbOn button configured")
directionLabel.config(text="FORWARD", fg='#00FF00')
# communicating with arduino
GPIO.output(22,GPIO.HIGH)
else:
#print('went to CbOff button')
directionBtn.config(image = Off_BtnImg)
directionBtn.image = Off_BtnImg
# print("CbOff button configured")
directionLabel.config(text="REVERSE", fg='#FF0000')
# communicating with arduino
GPIO.output(22,GPIO.LOW)
directionBool = not directionBool
def tempsensor():
while True:
print("bruh moment")
h, t = Adafruit_DHT.read_retry(SENSOR, SENSOR_PIN)
print(t)
print(h)
temp = "%.1F" %t
hum = "%.1f" %h
temperature.set(temp+ " *C")
humidity.set(hum+ " %")
time.sleep(1);
root = Tk()
app = App(root)
root.config(bg='black')
#root.attributes('-zoomed', True)
#root.state('fullscreen')
rootWidth = root.winfo_screenwidth()
rootHeight = root.winfo_screenheight()
root.attributes('-zoomed', True)
# Create mini window
#canvas = Canvas(root, bg='black', highlightbackground='white')
#canvas.place(relx=0.1, rely=0.03, relheight=0.51, relwidth=0.505)
temperature = StringVar()
temperature.set("----"+" *C")
humidity = StringVar()
humidity.set("----"+" %")
#root.after(2000, tempsensor)
h, t = Adafruit_DHT.read_retry(SENSOR, SENSOR_PIN)
On_img = Image.open("/home/pi/Downloads/on.png")
Off_img = Image.open("/home/pi/Downloads/off.png")
# Resize the image using resize() method according to the screen height and width
btnWidth = int(rootWidth / 6.4)
print(btnWidth)
infobtnWidth = int(rootHeight / 10)
print(infobtnWidth)
On_resize_img = On_img.resize((btnWidth, btnWidth))
Off_resize_img = Off_img.resize((btnWidth, btnWidth))
On_BtnImg = ImageTk.PhotoImage(On_resize_img)
Off_BtnImg = ImageTk.PhotoImage(Off_resize_img)
normalWidth = 1920 # Width of monitor screen used to write this code
normalHeight = 1080 # Height of monitor screen used to write this code
percentWidth = rootWidth / (normalWidth / 100)
percentHeight = rootHeight / (normalHeight / 100)
scale = ((percentWidth + percentHeight) / 2) / 100
fontsize = int(14 * scale)
fontsize = 50
fontstyle = tkFont.Font(family='Arial', size=fontsize)
titleFontsize = int(50 * scale)
if titleFontsize < 8:
titleFontsize = 8
TitleFontstyle = tkFont.Font(family="Gothic", size=titleFontsize)
## Labels ##
titleLabel = Label(root, text="MAX5487 DigiPot", font=TitleFontstyle, fg="red", bg="black")
titleLabel.place(relx=0.35, rely=0.05)
powerLabel = Label(root, text="POWER: OFF", font=fontstyle, fg='red', bg='black')
powerLabel.place(relx=0.2, rely=0.65, anchor=N)
directionLabel = Label(root, text="FORWARD", font=fontstyle, fg='#00FF00', bg='black')
directionLabel.place(relx=0.5, rely=0.65 , anchor=N)
powerBool = True
# boolean for led button
powerBtn = Button(root, image=Off_BtnImg, bg='black', bd=0, activebackground='black', highlightthickness = 0, command=PowerFn)
powerBtn.place(relx=0.2, rely=0.35, anchor=N)
directionBool = False
directionBtn = Button(root, image=On_BtnImg, bg='black', bd=0, activebackground='black', highlightthickness = 0, command=DirectionFn)
directionBtn.place(relx=0.5, rely=0.35, anchor=N)
templabel = Label(root, textvariable=temperature, font=fontstyle, fg='white', bg='red', highlightthickness = 0)
templabel.place(relx=0.2, rely=0.8, anchor=N)
humidlabel = Label(root, textvariable=humidity, font=fontstyle, fg='white', bg='red', highlightthickness = 0)
humidlabel.place(relx=0.5, rely=0.8, anchor=N)
# Button for closing
exit_button = Button(root, text="Exit", font=fontstyle, fg='white', bg='red', highlightthickness = 0, command=root.destroy)
exit_button.place(relx=0.5, rely=0.9, anchor=N)
background_thread = Thread(target=tempsensor)
background_thread.start()
root.mainloop()

Why is there white spaces when the button is pressed for my tkinter python clock

This is a clock that i just recently started, what i want to do is for the button to have each functions such as alarm and clock. I have done that but when i press the button white spaces would come out and the title would shift to the right and have a little indentation. and overall the design is just too weird as i just got on to tkinter i haven't learn much about frames.
import time
import tkinter as tk
#Initialise the window
clock = tk.Tk()
clock.title('Easy CLock')
clock.geometry('400x700')
clock.configure(bg='#121212')
border_effects = {
"flat": tk.FLAT,
"sunken": tk.SUNKEN,
"raised": tk.RAISED,
"groove": tk.GROOVE,
"ridge": tk.RIDGE,
}
#Time and Date function
def time_date():
# current time
current_time = time.strftime('%H:%M:%S')
current_date = time.strftime(r'%m/%d/%Y')
clock.after(200, time_date)
#Displays the time
c_time = tk.Label(f_time, text = current_time, fg='white', bg='#121212', font=('Verdana', 30))
c_date = tk.Label(f_time, text = current_date, font=('Verdana', 10), fg='white', bg='#121212')
c_time.grid(column=0, row=1)
c_date.grid(column=0, row=2)
#alarm button command
def alarm_func():
c_clicked = tk.Label(text='Alarm Interface', fg='white', bg='#121212')
c_clicked.grid(column=0, row=1)
#Creating Frames
f_header = tk.Frame(clock) #Header
f_time = tk.Frame(clock) #Clock Button
f_alarm = tk.Frame(clock) #Alarm Buttton
f_exit = tk.Frame(clock) #Exit button
#Setting the Frames with grid
f_header.grid(column=0 , row=0, columnspan = 3)
f_time.grid(column=0, row =3)
f_alarm.grid(column=1, row=3)
f_exit.grid(column=2, row =3)
#Setting label in the frame
f_lbl = tk.Label(f_header, text='Simplistic Clock', font=('Verdana', 30),fg='white', bg='#121212') # Purple text
time_but = tk.Button(f_time, text='Clock', command= time_date, bg='#f39c12', width = 15, relief = border_effects['ridge'])
alarm_but = tk.Button(f_alarm, text = 'Alarm', command = alarm_func, bg='#f39c12', width = 15, relief = border_effects['ridge'])
quit_but = tk.Button(f_exit, text='Exit', command = clock.quit, bg='#f39c12', width = 15, relief = border_effects['ridge'])
#Putting it on the frames
f_lbl.grid()
time_but.grid()
alarm_but.grid()
quit_but.grid()
clock.mainloop()
also, i want to hide the clock if the alarm button is pressed for example, if the user press the clock button first it will display the code , but when the user decide to press the alarm button i want the clock frame to be hided. i tired user .grid_forget() but it does't work for me. i am not sure about how the frames and gird work.
does the frame has its own column and grid as in each frame the starting would be column = 0, row = 0 or does it follow the parent window.

Raspberry Pi Python Tkinter image flicker problem

This is my first post and I have googled extensively for an answer but found nothing that works. I'm new to python but have some experience with C++/arduino programming.
I'm trying to make a weather station and display some garage door states as image icons. My issue is when it works, it flickers the images and eventually bogs down the system and runs very slowly. I've tried every combination I can think of making objects global or only changing certain parameters in the Label objects to work around the garbage collection issue I've read about. I've tried Canvas as well, but the issue I had with that is no matter what location coordinates I entered, it always showed up in the top center of the screen.
Edit: as per requested, heres a truncated version:
root = tk.Tk()
global garageOpenIcon
global garageClosedIcon
global doorUnlockedIcon
global doorLockedIcon
global doorOpenIcon
backgroundImage = PhotoImage(file = "background.gif")
garageOpenIcon = PhotoImage(file = "garageOpen.gif")
garageClosedIcon = PhotoImage(file = "garageClosed.gif")
doorLockedIcon = PhotoImage(file = "doorLocked.gif")
doorUnlockedIcon = PhotoImage(file = "doorUnlocked.gif")
doorOpenIcon = PhotoImage(file = "doorOpen.gif")
background = Label(root, image = backgroundImage)
background.place(x = 0, y = 0, relwidth = 1, relheight = 1)
global mainDoorLabel
global sideDoorLabel
mainDoorLabel = Label(root)
sideDoorLabel = Label(root)
def getDoors():
global garageOpenIcon
global garageClosedIcon
global doorOpenIcon
global doorUnlockedIcon
global doorLockedIcon
global mainDoorLabel
global sideDoorLabel
#side door open and unlocked:
if(GPIO.input(sideDoorPin) == GPIO.HIGH):
sideDoorLabel = Label(image = doorOpenIcon)
#closed and unlocked:
elif(GPIO.input(sideDoorPin) == GPIO.LOW):
if(GPIO.input(sideDoorLockPin) == GPIO.HIGH):
sideDoorLabel = Label(image = doorUnlockedIcon)
elif(GPIO.input(sideDoorPin) == GPIO.LOW):
sideDoorLabel = Label(image = doorLockedIcon)
#main door:
if(GPIO.input(mainDoorPin) == GPIO.HIGH):
mainDoorLabel = Label(image = garageOpenIcon)
else:
mainDoorLabel = Label(image = garageClosedIcon)
mainDoorLabel.place(x = 50, y = 400)
sideDoorLabel.place(x = 150, y = 400)
root.after(1000, getDoors)
Here is my full code, images work but flicker:
# WeatherStation for Raspberry Pi Model B Rev 2
# steve.a.mccluskey#gmail.com
#
# Code adapted from youtube.com/watch?v=MWKAitSX3vg
# Channel educ8s.tv
# Video name "Raspberry Pi Project: Touch Weather Station using a DHT22 and a Raspberry Pi 3 with TKInter GUI
#
# This program uses readings from several Dallas DS18B20 temp sensors and displays on the LCD along with on a website.
# Temps are collected from a background process called updateSensors.py and written to a JSON file called sensorValues.JSON
# which is located in the web folder at /var/www/html/. This program reads the JSON file. The webpage also reads it so there's
# minimal interferance between programs.
# Sensors are zero indexed. The sensors are assigned to their respective labels by their index number.
# Use readSensors.py to print their index number, digital ID and current temp to the console.
#
# Door sensors are read directly from this program and displayed accordingly. updateDoor.py is also run in background to write to doorSensorValues.json
# also in the web folder to be served to the web page.
#
# Hardware Used:
# Raspberry Pi Model B Rev 2
# Adafruit PITFT - Assembled 480x320 3.5" TFT+Touchscreen For Raspberry Pi, adafruit.com/product/2097
# Adafruit Prototyping Pi Plate Kit for Raspberry Pi, adafruit.com/product/801
# Sparkfun RJ45 Breakout sparkfun.com/products/716
# Sparkfun RJ45 8-Pin Connector sparkfun.com/products/643
# Dallas OneWire DS18B20 Digital Temp Sensors
#
#
#
#
# ------------
# GPIO Pins used:
# 1 ) 3.3v -> orange -> 3.3v
# 2 ) 5.0v
# 3 ) SDA -> white/brown -> I2C SDA
# 4 ) 5.0v
# 5 ) SCL -> brown -> I2C SCL
# 6 ) Gnd -> white/orange -> Gnd
# 7 ) GPIO 7 -> GPIO 4 -> white/green -> OneWire Bus
# 8 ) TXD
# 9 ) Gnd
# 10) RXD
# 11) GPIO 0 -> GPIO 17
# 12) GPIO 1 -> GPIO 18
# 13) GPIO 2 -> GPIO 27 -> blue -> Main Door Sensor
#
# 14) Gnd
# 15) GPIO 3 -> GPIO 22 -> white/blue -> Side Door Sensor
# 16) GPIO 4 -> GPIO 23 -> green -> Side Door Lock Sensor
# 17) 3.3v
# 18) GPIO 5 -> GPIO 24 -> LCD Shield
# 19) SPI MOSI -> LCD Shield
# 20) Gnd
# 21) SPI MISO -> LCD Shield
# 22) GPIO 6 -> GPIO 25 -> LCD Shield
# 23) SPI SCLK -> LCD Shield
# 24) SPI CE0 -> LCD Shield
# 25) Gnd
# 26) SPI CE1 -> LCD Shield
# -------
# Cat5e Pinout :
# White/Orange : Gnd
# Orange : 3.3v
# White/Green : OneWire
# Blue : Main Door Sensor
# White/Blue : Side Door Sensor
# Green : Side Door Lock Sensor
# White/Brown : I2C SDA
# Brown : I2C SCL
from Tkinter import *
import Tkinter as tk
from Tkinter import Canvas
from PIL import ImageTk, Image
import threading
import tkFont
import RPi.GPIO as GPIO
import json
import time
import datetime
#temp sensor assignments:
livingRoom = 1
upstairs = 4
basement = 0
outside = 2
garage = 3
sammyDoor = 5
#digital door sensor pins:
mainDoorPin = 27
sideDoorPin = 22
sideDoorLockPin = 23
GPIO.setmode(GPIO.BCM)
GPIO.setup(mainDoorPin, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(sideDoorPin, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(sideDoorLockPin, GPIO.IN, pull_up_down=GPIO.PUD_UP)
root = tk.Tk()
global garageOpenIcon
global garageClosedIcon
global doorUnlockedIcon
global doorLockedIcon
global doorOpenIcon
backgroundImage = PhotoImage(file = "background.gif")
garageOpenIcon = PhotoImage(file = "garageOpen.gif")
garageClosedIcon = PhotoImage(file = "garageClosed.gif")
doorLockedIcon = PhotoImage(file = "doorLocked.gif")
doorUnlockedIcon = PhotoImage(file = "doorUnlocked.gif")
doorOpenIcon = PhotoImage(file = "doorOpen.gif")
background = Label(root, image = backgroundImage)
background.place(x = 0, y = 0, relwidth = 1, relheight = 1)
global mainDoorLabel
global sideDoorLabel
global mainDoorState
global sideDoorState
mainDoorLabel = Label(root)
sideDoorLabel = Label(root)
#mainDoorLabel.place(x = 50, y = 400)
#sideDoorLabel.place(x = 150, y = 400)
#temp sensor strings:
mainTemp = StringVar()
mainTemp.set("In: ")
mainTempValue = StringVar()
outTemp = StringVar()
outTemp.set("Out:")
LR = StringVar()
LR.set("Living Room: ")
temperatureLR = StringVar()
UP = StringVar()
UP.set("Upstairs: ")
temperatureUp = StringVar()
DN = StringVar()
DN.set("Basement: ")
temperatureDn = StringVar()
Out = StringVar()
Out.set("Outside: ")
temperatureOut = StringVar()
Garage = StringVar()
Garage.set("Garage: ")
temperatureGg = StringVar()
SammyDoor = StringVar()
SammyDoor.set("SammyDoor: ")
temperatureSammyDoor = StringVar()
currentTime = StringVar()
timeStamp = StringVar()
#temp sensor labels:
mainTempLabel = Label(root, fg = "magenta2", background = "#00dbde", textvariable = mainTemp, font = ("Helvetica", 30))
mainTempLabel.place(x = 20, y = 195)
mainTempValueLabel = Label(root, fg = "magenta2", background = "#00dbde", textvariable = mainTempValue, font = ("Helvetica", 62, "bold"))
mainTempValueLabel.place(x = 100, y = 170)
outTempLabel = Label(root, fg = "magenta2", background = "#00dbde", textvariable = outTemp, font = ("Helvetica", 30))
outTempLabel.place(x = 20, y = 300)
outTempValueLabel = Label(root, fg = "magenta2", background = "#00dbde", textvariable = temperatureOut, font = ("Helvetica", 62, "bold"))
outTempValueLabel.place(x = 100, y = 260)
currentTimeLabel = Label(root, fg = "purple", background = "#00dbde", textvariable = currentTime, font = ("Helvetica", 30))
currentTimeLabel.place(x = 270, y = 5)
LRLabel = Label(root, fg = "white", background = "#00dbde", textvariable = LR, font = ("Helvetica", 25))
LRLabel.place(x = 391, y = 160)
temperatureLRLabel = Label(root, fg = "white", background = "#00dbde", textvariable = temperatureLR, font = ("Helvetica", 25, "bold"))
temperatureLRLabel.place(x = 600, y = 160)
UPLabel = Label(root, fg= "white", background = "#00dbde", textvariable = UP, font = ("Helvetica", 25))
UPLabel.place(x = 391, y = 210)
temperatureUpLabel = Label(root, fg = "white", background = "#00dbde", textvariable = temperatureUp, font = ("Helvetica", 25, "bold"))
temperatureUpLabel.place(x = 600, y = 210)
DNLabel = Label(root, fg = "white", background = "#00dbde", textvariable = DN, font = ("Helvetica", 25))
DNLabel.place(x = 391, y = 260)
temperatureDnLabel = Label(root, fg = "white", background = "#00dbde", textvariable = temperatureDn, font = ("Helvetica", 25, "bold"))
temperatureDnLabel.place(x = 600, y = 260)
GarageLabel = Label(root, fg = "white", background = "#00dbde", textvariable = Garage, font = ("Helvetica", 25))
GarageLabel.place(x = 391, y = 310)
temperatureGgLabel = Label(root, fg = "white", background = "#00dbde", textvariable = temperatureGg, font = ("Helvetica", 25, "bold"))
temperatureGgLabel.place(x = 600, y = 310)
SammyDoorLabel = Label(root, fg = "white", background = "#00dbde", textvariable = SammyDoor, font = ("Helvetica", 25))
SammyDoorLabel.place(x = 391, y = 360)
temperatureSammyDoorLabel = Label(root, fg = "white", background = "#00dbde", textvariable = temperatureSammyDoor, font = ("Helvetica", 25, "bold"))
temperatureSammyDoorLabel.place(x = 600, y = 360)
timeStampLabel = Label(root, fg = "white", background = "#00dbde", textvariable = timeStamp, font = ("Helvetica", 15))
timeStampLabel.place(x = 530, y = 440)
root.attributes("-fullscreen", True)
exitButton = tk.Button(root,fg = "white", text = "X", font = ("Helvetica", 20, "bold"), command = exit, bg = "red")
exitButton.place(x = 680, y = 0)
root.update_idletasks()
def exit():
root.quit()
def updateTemps():
index_value = []
id_value = []
temp_value = []
dateTime_value = []
#try reading json file. will not read if it is being written to by background process updateSensors.py
try:
with open('/var/www/html/sensorValues.json', 'r') as f:
data = f.read()
dataString = json.loads(data)
f.close()
for dateTime in dataString['timestamp']:
dateTime_value = (dateTime['dateTime'])
for index in dataString['sensors']:
temp_value.append(index['temp'])
id_value.append(index['id'])
index_value.append(index['index'])
temperatureLR.set(str(temp_value[livingRoom]) + " F")
temperatureOut.set(str(temp_value[outside]) + " F")
temperatureGg.set(str(temp_value[garage]) + " F")
temperatureUp.set(str(temp_value[upstairs]) + " F")
temperatureDn.set(str(temp_value[basement]) + " F")
temperatureSammyDoor.set(str(temp_value[sammyDoor]) + " F")
timeStamp.set(str(dateTime_value))
avg = format(float(((float(temp_value[livingRoom]) + float(temp_value[upstairs])) / 2.0)), '.1f')
mainTempValue.set(str(avg) + " F")
except:
pass
root.after(2000, updateTemps)
def getDoors():
global garageOpenIcon
global garageClosedIcon
global doorOpenIcon
global doorUnlockedIcon
global doorLockedIcon
global mainDoorLabel
global sideDoorLabel
# sideDoorState = 0
# mainDoorState = 0
#side door open and unlocked:
if(GPIO.input(sideDoorPin) == GPIO.HIGH):
# sideDoorState = 2
sideDoorLabel = Label(image = doorOpenIcon)
#closed and unlocked:
elif(GPIO.input(sideDoorPin) == GPIO.LOW):
if(GPIO.input(sideDoorLockPin) == GPIO.HIGH):
# sideDoorState = 1
sideDoorLabel = Label(image = doorUnlockedIcon)
elif(GPIO.input(sideDoorPin) == GPIO.LOW):
# sideDoorState = 0
sideDoorLabel = Label(image = doorLockedIcon)
#main door:
if(GPIO.input(mainDoorPin) == GPIO.HIGH):
# mainDoorState = 1
mainDoorLabel = Label(image = garageOpenIcon)
else:
mainDoorState = 0
mainDoorLabel = Label(image = garageClosedIcon)
mainDoorLabel.place(x = 50, y = 400)
sideDoorLabel.place(x = 150, y = 400)
root.after(1000, getDoors)
def getTime():
currentTime.set(datetime.datetime.now().strftime("%m-%d-%Y %H:%M:%S"))
root.after(500, getTime)
root.after(1000, getTime)
root.after(1001, updateTemps)
root.after(1000, getDoors)
root.mainloop()
maindoorlabel.configure(image = garageopenicon)
maindoorlabel.image = garageopenicon worked.

OptionMenu in tkinter keeps crashing when placed in a frame

I am trying to place an OptionMenu widget inside of a frame, which itself is inside of a notebook. From what I've found online, the code for doing this is roughly:
# add a drop down menu
hops = range(0,6)
self.selectedHop = StringVar(frame2)
self.selectedHop.set(hops[0])
self.hopOptions = OptionMenu(frame2, self.selectedHop, *hops)
self.hopOptions.grid(row=0, column=2, sticky=EW)
However, when I place this in my code in the code below (the chunk above is placed towards the bottom of it, and is labeled "PROBLEMATIC CODE..."), my app just freezes and I have to force quit it, and I have no error message to debug with. Any help would be appreciated.
#!/usr/bin/python3
from tkinter import *
from tkinter import ttk
from tkinter import messagebox
import subprocess
import sys
class ReportGUI:
def __init__(self, master):
self.master = master
master.title('Reporting')
master.resizable(True, True)
master.configure(background = '#b3e6cc')
master.minsize(width=800,height=700)
textcolor = "#003399"
self.style = ttk.Style()
self.style.configure('TFrame', background = '#e1d8b9')
self.style.configure('TButton', background = '#e1d8b9')
self.style.configure('TLabel', background = '#e1d8b9', font = ('Arial', 40))
self.style.configure('Header.TLabel', font = ('Arial', 30, 'bold'))
# step 1 - create notebook
self.notebook = ttk.Notebook(master)
self.notebook.pack()
# step 2 - create first frame to add to notebook
self.frame_logon = ttk.Frame(self.notebook)
# step 3 - add first frame to notebook and style it
self.notebook.add(self.frame_logon, text = 'Login')
self.frame_logon.config(padding = (20, 20, 20))
self.frame_logon.config(relief = RIDGE)
######### --- (1) LOGIN TAB ---- #########
label = ttk.Label(self.frame_logon, text = 'Administrative Reporting',
foreground=textcolor, style = 'Header.TLabel')
label.grid(row = 1, columnspan = 2)
# widget: username and password Label()
label2 = ttk.Label(self.frame_logon, text = 'Username:',
font = ('Arial', 17),foreground=textcolor)
label2.grid(row = 3, column = 0, padx = 5, sticky = 'sw')
label3 = ttk.Label(self.frame_logon, text = 'Password:',
font = ('Arial', 17),foreground=textcolor)
label3.grid(row = 3, column = 1, padx = 5, sticky = 'sw')
# widget: entry boxes Entry()
self.entry_name = ttk.Entry(self.frame_logon, width = 20, font = ('Arial', 15))
self.entry_pw = ttk.Entry(self.frame_logon, width = 20, font = ('Arial', 15))
# place the widgets
self.entry_name.grid(row = 4, column = 0, padx = 5)
self.entry_pw.grid(row = 4, column = 1, padx = 5)
self.entry_pw.config(show = '*') # make password not show
# widget: connect button Button()
self.loginButton = ttk.Button(self.frame_logon, text = 'Connect',
command = self.login)
self.loginButton.grid(row = 5, column = 1, columnspan = 2, padx = 1, pady = 1, sticky = 'e')
### COMMAND FUNCTIONS
def login(self):
# Make connections (TBA)
# 1) log into app
# 2) ssh into server port
# 3) connect to database
# if successful login and connection, launch reports tab
self.reportTab()
self.notebook.select(1) # switch tabs to reports tab
self.loginButton.state(['disabled']) # disable login button
# TAB 2: reporting tab
def reportTab(self):
# create report frame and add to notebook
self.frame_report = ttk.Frame(self.notebook)
self.notebook.add(self.frame_report, text = 'Report Options')
######### --- REPORT TAB ---- #########
#--------- FILTER 1: -----------
frame = ttk.Frame(self.frame_report)
frame.grid(row=1,column=0)
frame.config(height = 100, width = 200)
frame.config(relief = RIDGE)
ttk.LabelFrame(frame, height=100,width = 200,text = 'FILTER 1').pack()
#--------- FILTER 2: -----------
frame2 = ttk.Frame(self.frame_report)
frame2.grid(row=1,column=1)
frame2.config(height = 100, width = 200)
frame2.config(relief = RIDGE)
ttk.LabelFrame(frame2, height=100,width = 200,text = 'FILTER 2').pack()
#---------- PROBLEMATIC CODE: trying to add a drop down menu ----
hops = range(0,6)
self.selectedHop = StringVar(frame2)
self.selectedHop.set(hops[0])
self.hopOptions = OptionMenu(frame2, self.selectedHop, *hops)
self.hopOptions.grid(row=0, column=2, sticky=EW)
#----------------------------------------------------------------
#--------- FILTER 3: -----------
frame3 = ttk.Frame(self.frame_report)
frame3.grid(row=2,column=0)
frame3.config(height = 100, width = 200)
frame3.config(relief = RIDGE)
lbf3 = ttk.LabelFrame(frame3, height=100,width = 200,text = 'FILTER 3')
lbf3.pack()
#--------- FILTER 4: -----------
frame4 = ttk.Frame(self.frame_report)
frame4.grid(row=2,column=1)
frame4.config(height = 100, width = 200)
frame4.config(relief = RIDGE)
ttk.LabelFrame(frame4, height=100,width = 200,text = 'FILTER 4').pack()
# code for calling queries TBA
# launch results tab if queries successful
# self.resultsTab()
def func(self,value):
print(value)
# TAB 3: results tab
def resultsTab(self):
# create results frame and add to notebook
self.frame_results = ttk.Frame(self.notebook)
self.notebook.add(self.frame_results, text = 'Results')
def clear(self):
self.entry_name.delete(0, 'end')
self.entry_pw.delete(0, 'end')
self.text_comments.delete(1.0, 'end')
def main():
root = Tk()
hccwgui = ReportGUI(root)
root.mainloop()
if __name__ == "__main__": main()
Thanks in advance!
# ...
ttk.LabelFrame(frame2, height=100,width = 200,text = 'FILTER 2').pack()
# ...
self.hopOptions = OptionMenu(frame2, self.selectedHop, *hops)
self.hopOptions.grid(row=0, column=2, sticky=EW)
This is your problem. You're packing a LabelFrame in frame2, and then trying to grid something in frame2. A given container can only use one of grid() or pack()- using both won't cause an error, but the two managers will negotiate on how to place things for the rest of your lifetime.
The solution is to make sure that a given container's children are either packed or gridded, but never both in the same container (though you could have a structure parent->child->grandchild, where child is packed in parent and grandchild is gridded in child).

Raspberry Pi and Python (TKinter and Omxplayer)

we made an alarm clock program in python that uses TKinter to display the word "ALARM" when the current time equals the alarm time set by the user. Now we're trying to add an alarm sound to the program, so a sound will play when the current time reaches the alarm time set.
For some weird reason when the current time reaches the alarm time the alarm sound is opened and played about 7 times all at once and then exits.
We've tried a few different things to get it to just play the sound file once but nothing has worked. Do you guys have any suggestions at all? I can post more specific information/screenshots if need be. :)
Code so far:
import time
import subprocess
#GUI Setup
from Tkinter import *
alarm_window = Tk()
alarm_window.configure(bg = 'lightblue')
alarm_window.title('Alarm Clock!')
display = Label(alarm_window, font = ('Arial', 25), bg = 'lightblue', width = 13, height = 1, borderwidth = 2)
display.grid(row = 1, column = 1, columnspan = 6)
current_time = time.strftime("%H:%M:%S")
def refresh_time():
global current_time
current_time = time.strftime("%H:%M:%S")
if current_time == times.get():
alarm_window.configure(bg='red')
timelabel.configure(bg='red')
alarmdisplay = Label(alarm_window, font = ('Arial', 25), text = 'ALARM', bg='red', width = 13, height = 1, borderwidth = 2,)
alarmdisplay.grid(row = 2, column = 1, columnspan = 6)
playProcess = subprocess.Popen(['omxplayer', '/home/pi/Digital Alarm.mp3?dl=0'])
display.config(text=current_time)
display.after(10, refresh_time)
timelabel = Label(alarm_window, text = 'Enter H:M:S', bg = 'lightblue')
timelabel.grid(row = 2, column = 1)
times = Entry(alarm_window, width = 10, bg = 'lightgrey', justify = CENTER)
times.grid(row = 2, column = 2, columnspan = 5)
times.focus()
refresh_time()
alarm_window.mainloop()
Don't know omxplayer, but if it quits after playing the sound, you could simply wait for it to finish like:
playProcess = subprocess.Popen(['omxplayer', '/home/pi/Digital Alarm.mp3?dl=0'])
playProcess.wait()

Categories