so i've got some values coming in from an Arduino to my Raspberry Pi via an RF transceiver (NRF24L01) and i can display the integers when the program runs (Python). Now i want to display those integer values in my GUI that i've written in a seperate python script. I'm having trouble doing so. I've tried importing them from the GUI but it isn't working and i couldn't figure out why..
So now i've gone with the option of writing the value into a text file in the transmission script and then attempting to read the value from the text file in the GUI script but it still dosent work completely.
Can anyone help me update the text file from the transmission script and read it from the GUI script? Can you write to a text file from one script and read the text file from another script at the same time?
ANY help will be greatly appreciated. Thanks!
ps. If iv'e missed out on anything that you need to know just ask. It's a little hard to explain everything!
GUI CODE
# -*- coding: utf-8 -*-
"""
Created on Sat Aug 6 20:05:30 2016
#author: s
"""
import sys
if sys.version_info[0] < 3:
import Tkinter as tk
else:
import tkinter as tk
def clear():
pass
def exit_():
root.quit()
root.withdraw()
#water_amount = 0
water_cost = 0
total_water_amount = 0
total_water_cost = 0
def show_data():
while True:
text_file = open("Output.txt", "r")
water_amount = text_file.readlines()
text_file.close()
tk.Label(root, text='Water Amount: ' + str(water_amount)).pack()
tk.Label(root, text='Water Cost: ' + str(water_cost)).pack()
separator = tk.Frame(height=2, bd=10, relief=tk.SUNKEN)
separator.pack(fill=tk.X, padx=5, pady=5)
tk.Label(root, text='Total Water Amount: ' + str(total_water_amount)).pack()
tk.Label(root, text='Total Water Cost: ' + str(total_water_cost)).pack()
separator = tk.Frame(height=2, bd=10, relief=tk.SUNKEN)
separator.pack(fill=tk.X, padx=5, pady=5)
#show_data()
def get_rate():
import random
for i in range(100):
flow_rate.append(random.randint(20, 60))
# print(flow_rate)
# def draw_plot(flow_rate):
# import matplotlib.pyplot as plt
# conda install matplotlib
# print(flow_rate)
# plt.plot(flow_rate, label='Flow rate ml/sec')
# plt.xlabel('Time(sec)')
# plt.ylabel('Flow Rate(ml)')
# plt.title("Flow Rate Chart")
#
# plt.legend()
# plt.show()
root = tk.Tk(className='Water')
flow_rate = []
get_rate()
show_data()
tk.Button(root, text='Clear', command=clear).pack(side='left')
tk.Button(root, text='Exit', command=exit_).pack(side='left')
#tk.Button(root, text='Draw', command=draw_plot(flow_rate)).pack_forget()
root.mainloop()
CODE RECEIVING VALUES
import RPi.GPIO as GPIO
from lib_nrf24 import NRF24
import time
import spidev
GPIO.setmode(GPIO.BCM)
pipes = [[0xE8, 0xE8, 0xF0, 0xF0, 0xE1], [0xF0, 0xF0, 0xF0, 0xF0, 0xE1]]
radio = NRF24(GPIO, spidev.SpiDev())
radio.begin(0,17)
radio.setPayloadSize(32) #can have maximum 32
radio.setChannel(0x76)
radio.setDataRate(NRF24.BR_1MBPS) #Slower since it is secure
radio.setPALevel(NRF24.PA_MIN) # Minimum to save battery
radio.setAutoAck(True)
radio.enableDynamicPayloads()
radio.enableAckPayload() #Acknowledgement Payload : Can verify if data received
radio.openReadingPipe(1, pipes[1])
radio.printDetails()
radio.startListening()
while True:
# Waits to recieve data, if no data is recieved then goes into sleep mode
while not radio.available(0):
time.sleep(1/100)
receivedMessage = []
#Populates the message
radio.read(receivedMessage, radio.getDynamicPayloadSize())
#-------------------------------------------------------
raw = int(receivedMessage[1]) * 256
total = raw + int(receivedMessage[0])
print ("total equals:" + str(int(total)))
text_file = open("Output.txt", "w")
text_file.write("%s" % total)
text_file.close()
You should try to combine the data-receiving code and data-displaying code with threading library.
In the while True loop in the data-receiving script, it should check for new result and notify the GUI thread somehow (eg. store it in a global variable and use the threading.Condition object), or change the GUI directly.
For example:
from tkinter import *
import threading
tk=Tk()
result=StringVar()
Label(tk,textvariable=result).pack()
def update_result():
import RPi.GPIO as GPIO
from lib_nrf24 import NRF24
import time
import spidev
GPIO.setmode(GPIO.BCM)
pipes = [[0xE8, 0xE8, 0xF0, 0xF0, 0xE1], [0xF0, 0xF0, 0xF0, 0xF0, 0xE1]]
radio = NRF24(GPIO, spidev.SpiDev())
radio.begin(0,17)
radio.setPayloadSize(32) #can have maximum 32
radio.setChannel(0x76)
radio.setDataRate(NRF24.BR_1MBPS) #Slower since it is secure
radio.setPALevel(NRF24.PA_MIN) # Minimum to save battery
radio.setAutoAck(True)
radio.enableDynamicPayloads()
radio.enableAckPayload() #Acknowledgement Payload : Can verify if data received
radio.openReadingPipe(1, pipes[1])
radio.printDetails()
radio.startListening()
while True:
while not radio.available(0):
time.sleep(1/100)
receivedMessage = []
#Populates the message
radio.read(receivedMessage, radio.getDynamicPayloadSize())
#-------------------------------------------------------
raw = int(receivedMessage[1]) * 256
total = raw + int(receivedMessage[0])
result.set(total)
threading.Thread(target=update_result).start()
mainloop()
(I didn't test this program because I don't have the environment, but I think that should work. Please comment if it's not working.)
Related
so I am making a program on tkinter that gets a response from a server and depending on the answer, it will change the background color, to either green for success or red for error, the problem is that I realized that when running the code, the windows.after() method doesn't wait till is done to continue and when I do the request for the server, it have to do it three times to check if the response is correct, and it is suppossed to change the window background color each time, but it is only doing it one time. And not only the background color changing fails, also I want to change a label's text when it is doing the request,but it does it really quick and I'm not able to diferentiate the changes, so the question is: how can I
How can I make the program wait until one line finishes running to go to the next one and not everything happens at the same time and so fast?
Here is a piece of my code, I removed the request part because I'm trying to solve this problem first:
# import gpiozero
# import picamera
import json
import requests
import tkinter as tk
with open("config.json") as file:
config = json.load(file)
ENDPOINT = config["ENDPOINT"]
USUARIO = config["USUARIO"]
ESTACION = config["ESTACION"]
TIEMPO_ESPERA = config["TIEMPO_ESPERA"]
PIN_RELE = config["PIN_RELE"]
PATH_SALIDA = ENDPOINT + "Salida.getTicket/" + ESTACION + "/" + USUARIO + "/"
barcode = ""
# RELAY = gpiozero.OutputDevice(PIN_RELE, active_high=True, initial_value=False)
# CAMERA = picamera.PiCamera()
def check_scan_barcode(event=None):
info_label.config(text = "Wait...")
barcode = barcode_entry.get()
barcode_entry.delete(0, "end")
for i in range(3):
response = get_request(ENDPOINT + barcode)
if response["data"] == "True":
success()
open_barrier()
else:
error()
info_label.config(text = "Scan barcode")
def get_request(url):
response = requests.get(url)
response.raise_for_status()
response = response.json()
return response
def normal():
window.configure(bg="white")
info_label.configure(bg="white")
def success():
window.configure(bg="green")
info_label.configure(bg="green")
window.after(1000, normal)
def error():
window.configure(bg="red")
info_label.configure(bg="red")
window.after(1000, normal)
def open_barrier(barcode):
# CAMERA.capture(f"/home/pi/Pictures{barcode}.jpg")
# RELAY.on()
# window.after(TIEMPO_ESPERA, RELAY.off)
pass
window = tk.Tk()
# window.attributes('-fullscreen', True)
info_label = tk.Label(window, text= "Scan barcode.", font=("Arial", 40))
info_label.pack()
barcode_entry = tk.Entry(window, width=50)
barcode_entry.bind('<Return>', check_scan_barcode)
barcode_entry.pack(expand=True)
barcode_entry.focus()
window.mainloop()
my project is to build a scanner that send the sensor value on Serial port. I want to control the scanner using a GUI Tkinter, so I want to check if something is coming on the serial continuously. However, I used the .after() function that works when something is sent but when the scanner is "waiting" and nothing is sent, the GUI freezes and I can't to do anything until something is sent.
Thanks,
Here's the code triggered by the main button:
def Acqard():
global flag
flag = 1
arduinoData.write(b'1')
log.insert(END, "Début du scan\n")
root.after(10, write_data)
And here are the functions that save the DATA in a txt file:
def write_data():
global file_stream
file_stream = open("data.txt", "a") # mode write ou append ?
write_lines()
def write_lines():
global after_id
data = arduinoData.read()
try:
data2 = data.decode("utf-8")
file_stream.write(data2)
print(data2)
if data2 == "F":
root.after_cancel(after_id)
print("Ca a marché")
stopacq()
after_id = root.after(10, write_data)
except:
return
And here's the function that stops the scanner:
def stopacq():
global flag, file_stream
flag = 0
root.after_cancel(after_id)# Annulation des rappels automatiques de write_lines
file_stream.close()
file_stream = None
arduinoData.write(b'3')
log.insert(END, "Scan interrompu\n")
I have been trying to display the temperature sensor values in python shell which is connected with Arduino(connected to my laptop through USB port)
I am trying to get the values of the serial port using python package serial.tools.list_ports but while using mentioned below code
import serial
import json
import tkinter
from tkinter import messagebox
from tkinter import *
import tkinter as ttk
import serial.tools.list_ports
ard = serial.Serial();
root = ttk.Tk()
root.title("Read Sensor")
B = None
C = None
ser_dict = {}
# Add a grid
mainframe = Frame(root)
mainframe.grid(column=0,row=0, sticky=(N,W,E,S) )
mainframe.columnconfigure(0, weight = 1)
mainframe.rowconfigure(0, weight = 1)
mainframe.pack(pady = 100, padx = 100)
# Create a Tkinter variable
tkvar1 = StringVar(root)
tkvar = StringVar(root)
#Serial Port
a=serial.tools.list_ports.comports()
for w in a:
print(w.device)
k = [w.device]
print(k)
ser_dict = { i for i in k }
print (ser_dict)
val1 = tkvar1.get()
if val1 in ser_dict:
ard.port = str (ser_dict[val1])
ard.isOpen()
if C:
C.destroy()
C = ttk.Button(root, text =val1, command = dropCall)
C.pack()
# Dictionary with options
baud = { '9600','119200','34800'}
#Pop Up desciption
popupMenu1 = OptionMenu(mainframe, tkvar1, *ser_dict)
Label(mainframe, text="Serial Port").grid(row = 1, column = 1)
popupMenu1.grid(row = 2, column =1)
popupMenu2 = OptionMenu(mainframe, tkvar, *baud)
Label(mainframe, text="Baudrate").grid(row = 3, column = 1)
popupMenu2.grid(row = 4, column =1)
#Serial Callback Functions
def helloCallBack():
k = ard.readline().decode('ascii');
if(len(k)>0):
print (k);
size = len(k);
#print (k[0:size-2]);
print (size);
messagebox.showinfo('Message From Arduino',k[0:size-2]+'\n'+str(size))
#def portCall(*kargs):
#global C
#global ser_dict
#baudrate functions
def dropCall(*args):
global B
value = tkvar.get()
## using a dictionary instead of if statements
## to show how dictionaries are used
baud_dict={'9600':value, '34800':value, '119200':value}
if value in baud_dict:
ard.baudrate = int(baud_dict[value])
if B:
B.destroy()
B = ttk.Button(root, text =value, command = helloCallBack)
B.pack()
#Link Function
tkvar.trace('w', dropCall)
I have to face the error in which I am not able to open the serial port.
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\Misha\AppData\Local\Programs\Python\Python36\lib\tkinter\__init__.py", line 1702, in __call__
return self.func(*args)
File "C:\Users\Misha\Desktop\test\GUItest.py", line 61, in helloCallBack
k = ard.readline().decode('ascii');
File "C:\Users\Misha\AppData\Local\Programs\Python\Python36\lib\site-packages\serial\serialwin32.py", line 267, in read
raise portNotOpenError
serial.serialutil.SerialException: Attempting to use a port that is not open
Suggestion on this will be a great help.
Please find some example code that finds and opens the serial port connection to a device connected to a serial port. This is tested with Python 3.6 under Linux. It should work under Windows, but I have not tested this. I use PID and VID to select the attached device as:
There may be several active serial ports.
The port name can change when you reconnect your device.
It is more robust across different OSs. Windows calls ports 'COMx' and Linux uses 'ttyx'.
The PID and VID of your Arduino may be different than in my example. The script will list the PIDs and VIDs of all connected devices. Alter PID_VARIABLE and VID_VARIABLE to the one for your Arduino.
import logging
import serial
import serial.tools.list_ports as list_ports
from time import sleep
BAUD = 115200
PID_TARGET = 67
VID_TARGET= 9025
TIMEOUT = 0.1
logging.basicConfig(level=logging.DEBUG, format='%(message)s')
class SerialPort():
def __init__(self, pid=PID_TARGET, vid=VID_TARGET, baud=BAUD, timeout=TIMEOUT):
self.serial_port = self.open_serial_port(pid, vid, baud, timeout)
def get_serial_data(self, serial_port):
''' get serial port data '''
inWaiting = serial_port.inWaiting()
read_bytes = serial_port.readline(inWaiting)
if not read_bytes:
return
return read_bytes.decode()
def get_serial_port(self):
''' Return the serial port. '''
return self.serial_port
def open_serial_port(self, pid=PID_TARGET, vid=VID_TARGET, baud=BAUD, timeout=TIMEOUT):
''' Open a serial connection. '''
print('looking for attached microbit on a serial port')
serial_port = serial.Serial(timeout=timeout)
serial_port.baudrate = baud
ports = list(list_ports.comports())
print('scanning ports')
ports.sort(reverse=True)
for p in ports:
print('pid: {} vid: {} device: {}'.format(p.pid, p.vid, p.device))
if (p.pid == pid) and (p.vid == vid):
print('found target device pid: {} vid: {} port: {}'.format(
p.pid, p.vid, p.device))
serial_port.port = str(p.device)
if not serial:
print('no serial port found')
return None
try:
serial_port.open()
serial_port.flush()
print('opened serial port: {}'.format(serial_port.port))
except Exception as e:
print('cannot open serial port: {}'.format(e))
return None
sleep(0.1)
return serial_port
if __name__ == '__main__':
print('instatiating SerialPort()')
serial_port = SerialPort()
print('finished')
In this script I am taking the temperature from a DHT11 sensor and parsing the data that another script can read. Everything works except for writing the file to another pc using the path I placed in the f = open part of the script below. Everything works great except that the file doesn't get written or saved.
Any Help?
#!/usr/bin/env python
# encoding: utf-8
import sys
import time
import dht11
import RPi.GPIO as GPIO
#define GPIO 14 as DHT11 data pin
Temp_sensor=14
def main():
# Main program block
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM) # Use BCM GPIO numbers
instance = dht11.DHT11(pin = Temp_sensor)
while True:
#get DHT11 sensor value
result = instance.read()
temp = '{:.0f}'.format(result.temperature * 1.8 + 32)+"°"
# The path to send the txt file to and save is /10.1.1.28/c$/Temperature_RETR/kvoa_temp.txt
if result.is_valid():
print temp
f = open('\\10.1.1.28\c$\Temperature_RETR\new_temp.txt','w')
#f = open('/home/pi/Desktop/new_temp.txt','w')
y = temp
z = str(y)
f.write(z)
f.close()
time.sleep(60) # 60 second delay
if __name__ == '__main__':
try:
main()
except KeyboardInterrupt:
pass
I need a progress to show during file download for Python 3.
I have seen a few topics on Stackoverflow, but considering that I'm a noob at programming and nobody posted a complete example, just fractions of it, or the one that I can make work on Python 3, none are good for me...
additional info:
ok, so i have this:
from urllib.request import urlopen
import configparser
#checks for files which need to be downloaded
print(' Downloading...')
file = urlopen(file_url)
#progress bar here
output = open('downloaded_file.py','wb')
output.write(file.read())
output.close()
os.system('downloaded_file.py')
script is run through python command line
There is urlretrieve() that downloads an url to a file and allows to specify a reporthook callback to report progess:
#!/usr/bin/env python3
import sys
from urllib.request import urlretrieve
def reporthook(blocknum, blocksize, totalsize):
readsofar = blocknum * blocksize
if totalsize > 0:
percent = readsofar * 1e2 / totalsize
s = "\r%5.1f%% %*d / %d" % (
percent, len(str(totalsize)), readsofar, totalsize)
sys.stderr.write(s)
if readsofar >= totalsize: # near the end
sys.stderr.write("\n")
else: # total size is unknown
sys.stderr.write("read %d\n" % (readsofar,))
urlretrieve(url, 'downloaded_file.py', reporthook)
Here's a GUI progress bar:
import sys
from threading import Event, Thread
from tkinter import Tk, ttk
from urllib.request import urlretrieve
def download(url, filename):
root = progressbar = quit_id = None
ready = Event()
def reporthook(blocknum, blocksize, totalsize):
nonlocal quit_id
if blocknum == 0: # started downloading
def guiloop():
nonlocal root, progressbar
root = Tk()
root.withdraw() # hide
progressbar = ttk.Progressbar(root, length=400)
progressbar.grid()
# show progress bar if the download takes more than .5 seconds
root.after(500, root.deiconify)
ready.set() # gui is ready
root.mainloop()
Thread(target=guiloop).start()
ready.wait(1) # wait until gui is ready
percent = blocknum * blocksize * 1e2 / totalsize # assume totalsize > 0
if quit_id is None:
root.title('%%%.0f %s' % (percent, filename,))
progressbar['value'] = percent # report progress
if percent >= 100: # finishing download
quit_id = root.after(0, root.destroy) # close GUI
return urlretrieve(url, filename, reporthook)
download(url, 'downloaded_file.py')
On Python 3.3 urlretrieve() has different reporthook interface (see issue 16409). To workaround it, you could access the previous interface via FancyURLopener:
from urllib.request import FancyURLopener
urlretrieve = FancyURLopener().retrieve
To update the progress bar within the same thread, you could inline urlretrieve() code:
from tkinter import Tk, ttk
from urllib.request import urlopen
def download2(url, filename):
response = urlopen(url)
totalsize = int(response.headers['Content-Length']) # assume correct header
outputfile = open(filename, 'wb')
def download_chunk(readsofar=0, chunksize=1 << 13):
# report progress
percent = readsofar * 1e2 / totalsize # assume totalsize > 0
root.title('%%%.0f %s' % (percent, filename,))
progressbar['value'] = percent
# download chunk
data = response.read(chunksize)
if not data: # finished downloading
outputfile.close()
root.destroy() # close GUI
else:
outputfile.write(data) # save to filename
# schedule to download the next chunk
root.after(0, download_chunk, readsofar + len(data), chunksize)
# setup GUI to show progress
root = Tk()
root.withdraw() # hide
progressbar = ttk.Progressbar(root, length=400)
progressbar.grid()
# show progress bar if the download takes more than .5 seconds
root.after(500, root.deiconify)
root.after(0, download_chunk)
root.mainloop()
download2(url, 'downloaded_file.py')
I think this piece of code can help you. I'm not quite sure it's exactly what you want. At least it should give you something to work on.
import tkinter
from tkinter import ttk
from urllib.request import urlopen
def download(event):
file = urlopen('http://www.python.org/')
output = open('downloaded_file.txt', 'wb')
lines= file.readlines()
i = len(lines)
for line in lines:
output.write(line)
pbar.step(100/i)
output.close()
file.close()
root = tkinter.Tk()
root.title('Download bar')
pbar = ttk.Progressbar(root, length=300)
pbar.pack(padx=5, pady=5)
btn = tkinter.Button(root, text="Download")
# bind to left mouse button click
btn.bind("<Button-1>", download)
btn.pack(pady=10)
root.mainloop()
This works, I've tried it.