I'm fairly new to Python. Here's a script I have that gathers info from our MySQL server hosting our Helpdesk tickets, and will pop up a message box (using EasyGUI's "msgbox()" function) whenever a new ticket arrives.
The issue is that I want my program to continue processing after the popup, regardless of whether the user clicks "OK" or not, even if that means message boxes could keep popping up over each other and must be dismissed one by one; that would be fine with me.
I looked into threading, and either it doesn't work or I did something wrong and need a good guide. Here's my code:
import MySQLdb
import time
from easygui import *
# Connect
db = MySQLdb.connect(host="MySQL.MyDomain.com", user="user", passwd="pass", db="db")
cursor = db.cursor()
# Before-and-after arrays to compare; A change means a new ticket arrived
IDarray = ([0,0,0])
IDarray_prev = ([0,0,0])
# Compare the latest 3 tickets since more than 1 may arrive in my time interval
cursor.execute("SELECT id FROM Tickets ORDER BY id DESC limit 3;")
numrows = int(cursor.rowcount)
for x in range(0,numrows):
row = cursor.fetchone()
for num in row:
IDarray_prev[x] = int(num)
cursor.close()
db.commit()
while 1:
cursor = db.cursor()
cursor.execute("SELECT id FROM Tickets ORDER BY id DESC limit 3;")
numrows = int(cursor.rowcount)
for x in range(0,numrows):
row = cursor.fetchone()
for num in row:
IDarray[x] = int(num)
if(IDarray != IDarray_prev):
cursor.execute("SELECT Subject FROM Tickets ORDER BY id DESC limit 1;")
subject = cursor.fetchone()
for line in subject:
# -----------------------------------------
# STACKOVERFLOW, HERE IS THE MSGBOX LINE!!!
# -----------------------------------------
msgbox("A new ticket has arrived:\n"+line)
# My time interval -- Checks the database every 8 seconds:
time.sleep(8)
IDarray_prev = IDarray[:]
cursor.close()
db.commit()
You can use Python GTK+
It offers non-modal using
set_modal(False)
Related
I am a total beginner and I think I underestimated my little project.
I am trying to implement a simple attendance system that will give me the hours worked per day and later per month.
I am using a Raspberry pi 3 b+ and RC522 Rfid reader plus 16x2 lcd display.
The data ist stored in a database using MariaDB.
The idea is to use it for student workers in a restaurant to clock in their hours.
The employees still write down their hours, but if it works it could replace the paperwork, we will see.
I know that there will be some concerns about legality, but thats up for the lawyers once I am done.
However my issue is, that right now I am unable to clock in and clock out multiple users.
It does work for one user.
If I clock in User 1 it waits until there is a new clock out info, doesn't matter which user it is.
So user 1 clock in, user 2 wants to clock in but he is registered to clock out and only then the database entry is transferred. I think it somehow would need to update the entries instantly.
I think you can get the idea from the picture
phpMyAdminScreenshot
I think I need to get more info from the database and compare it to what I have.
But I hit a wall now and I am unable to find a solution for my problem.
The code I have right now:
'#!/usr/bin/env python
import time
import datetime
import RPi.GPIO as GPIO
from mfrc522 import SimpleMFRC522
import mysql.connector
import drivers
db = mysql.connector.connect(
host="localhost",
user="xxx",
passwd="xxx",
database="attendancesystem"
)
cursor = db.cursor()
reader = SimpleMFRC522()
display = drivers.Lcd()
sign_in = 0
sign_out= 1
try:
while True:
display.lcd_clear()
display.lcd_display_string("Transponder", 1)
display.lcd_display_string("platzieren", 2)
id, text = reader.read()
ts = time.time()
timestamp = datetime.datetime.fromtimestamp(ts).strftime('%Y-%m-%d %H:%M:%S')
cursor.execute("Select id, name FROM users WHERE rfid_uid="+str(id))
result = cursor.fetchone()
display.lcd_clear()
#if cursor.rowcount >= 1:
#display.lcd_display_string("Willkommen " + result[1], 2)
#cursor.execute("INSERT INTO attendance (user_id) VALUES (%s)", (result[0],) )
if sign_in == 0:
sign_in = (sign_in +1) % 2
sign_out = (sign_out +1) % 2
cursor.execute(f"INSERT INTO attendance (user_id, clock_in, signed_in) VALUES (%s, %s, %s)", (result[0], timestamp, sign_in) )
display.lcd_display_string(f"Angemeldet " + result[1], 1)
elif sign_in == 1:
sign_out = (sign_out +1) % 2
sign_in = (sign_in +1) % 2
cursor.execute(f"INSERT INTO attendance (user_id, clock_out, signed_in) VALUES (%s, %s, %s)", (result[0], timestamp, sign_in) )
display.lcd_display_string (f"Abgemeldet " + result[1], 1)
db.commit()
else:
display.lcd_display_string("Existiert nicht.", 1)
time.sleep(2)
finally:
GPIO.cleanup()'
My idea was to get one more database entry called signed_in and either have it as 0 or as 1.
The signed_in status does update how I want it to, but I don't know how to continue from here.
And I fail to be able to update the table I want to.
My idea was to get user_id and check for this id the last status of the signed_in row, if it is 1 the timestamp will update the clock_out row and signed_in to 0.
If it is 0 and clock_out is not NULL it will start a new row with the clock_in timestamp and switch signed_in to 1.
I didn't have any luck with updating any database values, so I reverted back to INSERT.
I would expect the database would only store events. These events would be from when they touched the RFID. The card would have an ID/employee number.
Processing the database information would allow the calculation of who is on shift and the length of shifts worked etc.
If there was an odd number of entries for an employee then you could assume they are on shift. Even number of entries would mean they have completed the shift.
I don't have your hardware or database so I've created random RFID read events and used sqlite3.
import datetime
import random
import sqlite3
import time
class SimpleMFRC522:
#staticmethod
def read():
while random.randint(0, 30) != 10: # Create some delay/blocking
time.sleep(1)
employee_id = random.randint(0, 5)
return employee_id, f'employee_{employee_id}'
class MyDatabase:
def __init__(self):
self.db = sqlite3.connect('/tmp/my-test.db')
with self.db:
self.db.execute("""
CREATE TABLE IF NOT EXISTS workers (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
empl_no INTEGER,
name TEXT,
tap_event timestamp);
""")
self.db.commit()
def insert_event(self, empl_no, name, timestamp):
sqlite_insert_with_param = """INSERT INTO 'workers'
('empl_no', 'name', 'tap_event')
VALUES (?, ?, ?);"""
self.db.cursor()
self.db.execute(sqlite_insert_with_param, (empl_no, name, timestamp))
self.db.commit()
def worker_in(self, empl_no):
sql_cmd = f"SELECT COUNT(*) FROM workers WHERE empl_no = {empl_no};"
cursor = self.db.execute(sql_cmd)
event_count, = cursor.fetchone()
return event_count % 2 == 1 and event_count > 0
def last_shift(self, empl_no):
sql_cmd = f"""SELECT tap_event FROM
(SELECT * FROM workers WHERE empl_no = {empl_no} ORDER BY tap_event DESC LIMiT 2)
ORDER BY tap_event ASC ;"""
cursor = self.db.execute(sql_cmd)
tap_in, tap_out = cursor.fetchall()
start = datetime.datetime.fromtimestamp(tap_in[0])
end = datetime.datetime.fromtimestamp(tap_out[0])
return end - start
def main():
db = MyDatabase()
reader = SimpleMFRC522()
while True:
empl_no, name = reader.read()
print(f"adding tap event for {name}")
db.insert_event(empl_no, name, datetime.datetime.timestamp(datetime.datetime.now()))
if db.worker_in(empl_no):
print(f"\t{name} has started their shift")
else:
time_worked = db.last_shift(empl_no)
print(f"\t{name} has left the building after {time_worked}")
if __name__ == '__main__':
main()
This gave me a transcript as follows
adding tap event for employee_5
employee_5 has started their shift
adding tap event for employee_0
employee_0 has left the building after 0:02:10.154697
adding tap event for employee_3
employee_3 has left the building after 0:07:02.465903
adding tap event for employee_3
employee_3 has started their shift
adding tap event for employee_2
employee_2 has left the building after 0:06:27.403874
adding tap event for employee_2
employee_2 has started their shift
When I run the below code, it continues to return the same information even if I change the data saved in the database or insert another row into the database. When I restart the script it pulls the new updated information. I would like the program to pull the most up to date data.
Any help would be greatly appreciated
def readLastTemp():
cur = db.cursor()
sql = "SELECT Temperature FROM Temperatures ORDER BY ID DESC LIMIT 1"
cur.execute(sql)
results = cur.fetchall()
cur.close()
for row in results:
Temperature = row[0]
return Temperature
while True:
print(readLastTemp())
time.sleep(1)
I am new to tkinter , I am searching a way so that i can easily show my two tables Student and Issue Book table in database using roll number which is common in both ( and it is a primary key ) to the tkinter GUI Student Detail window. The idea is when i enter the roll number it shows the table record in student details as i mentioned the specific frames in the Gui and So how to make a function that display my database data to tkinter Gui .I am giving my Program ,please help me to give a clarify solution.
Students_details.py
The code for fetching data from database through an id and display it into two tables in the GUI is :
I made two functions one for fetching first table data .
def details():
rollnum = rnum.get()
print(rollnum)
conn = pymysql.connect(host='localhost', user='root', password='', db='data')
a = conn.cursor()
a.execute("select * from student where rollno='"+rollnum+"'")
results = a.fetchall()
count = a.rowcount
print(results)
print(count)
if count > 0:
for row in results:
rnum1.set(row[0])
sname.set(row[1])
fanm.set(row[2])
mtnm.set(row[3])
dateob.set(row[4])
bran.set(row[5])
else:
messagebox.showinfo("record not found")
conn.close()
and second for fetching another table from database
def bookdetails():
rollnum = rnum.get()
print(rollnum)
conn = pymysql.connect(host='localhost', user='root', password='', db='data')
b = conn.cursor()
b.execute("select * from issuebook where rollno='" + rollnum + "'")
resultb = b.fetchall()
countb = b.rowcount
print(resultb)
print(countb)
if countb > 0:
for row in resultb:
booknm.set(row[1])
booknum.set(row[2])
dateofiss.set(row[3])
lstdate.set(row[4])
else:
messagebox.showinfo("record not found")
conn.close()
I created another function for calling these two function
def details_and_bookdetails():
details()
bookdetails()
Then I passed the function details_and_bookdetails in the button through command.
I have my python script which reads an excel column row by row and returns all rows str(values).
I want to write another script which will allow put these values to sql db. I've already written connect method:
def db_connect():
adr = 'some_addr'
uid = 'some_uid'
pwd = 'pwd'
port = port
dsn_tns = cx_Oracle.makedsn(adr, port, SID)
db = cx_Oracle.connect('username', 'pass', dsn_tns)
cur = db.cursor()
cur.execute('update TABLE set ROW = 666 where ANOTHER_ROW is null')
db.commit()
This method does an update but it sets 666 for ALL rows. How to do it by kind of iteration in sql? For example, first row of output == 1, second == 23, third == 888.
If I understand correctly what you are trying to do here it should be done in two phases. First select all rows for update (based on chosen condition), then you can iteratively update each of these rows.
It cannot be done in single query (or on only single condition that does not change through a number of queries), because SQL works on sets, that's why each time your query is executed you are updating whole table, and in the end only getting result of the last query.
You can use the "rownum" expression, as in:
cur.execute("update TABLE set ROW = rownum where ANOTHER_ROW is null")
This will start with the value 1 and increment up by one for each row updated.
If you want more control over the value to set, you can also do the following in PL/SQL (untested):
cur.execute("""
declare
t_NewValue number;
cursor c_Data is
select ROW, ANOTHER_ROW
from TABLE
where ANOTHER_ROW is null
for update;
begin
t_NewValue := 1;
for row in c_Data loop
update TABLE set ROW = t_NewValue
where current of c_Data;
t_NewValue := t_NewValue + 1;
end loop;
end;""")
This gives you the most control. You can use whatever logic you require to control what the new value should be.
Please take a look at another method which is writing to excel:
adr = 'some_addr'
uid = 'some_uid'
pwd = 'pwd'
port = port
dsn_tns = cx_Oracle.makedsn(adr, port, SID)
db = cx_Oracle.connect('username', 'pass', dsn_tns)
cur = db.cursor()
cells = excel.read_from_cell()
indices_and_statuses = []
stat = execute_script(some_js)
for req_id in cells:
indices_and_statuses.append((cells.index(req_id), stat))
cur.execute("""update TABLE set ROW ="""+"'"+req_id+"'"+"""where ANOTHER_ROW is null""")
db.commit()
db.close()
And in this code when you put print(req_id) in this FOR statement, you will see that req_id is changing. But in DB only the last req_id is saved.
I have a python script that read data from a MySQL db. There a table called ORARI and basically 3 fields: ID, acceso,spento. I need to read acceso, spento every 10 seconds. ACCESO and SPENTO are edited via a web interface, so they may vary. The problem is that when I run my script i can see the exact data from the db, but when I make a change to these values, the python script show me the initial value, not the updated value.
while True:
time.sleep(10)
dateString = strftime('%H:%M:%S')
orario = ("SELECT * FROM orari WHERE attivo = 1")
cur.execute(orario)
row = cur.fetchone()
acceso = row[1]
spento = row[2]
print acceso
print dateString
print spento
need to insert, after the query: db.commit()