Notifications
Clear all

SQLite3 Thread Error on Pi

3 Posts
2 Users
1 Likes
399 Views
MadMisha
(@madmisha)
Member
Joined: 4 years ago
Posts: 340
Topic starter  

Right now I have python file that automatically runs on startup through crontab. Originally, button click has a callback to pull a txt file, read the last line and either edit it or enter a new line. It has worked for a few years now. I am now attempting to change it over to a SQLite3 database. I am using the same function that has worked and replacing the file read and write to the SQLite3. Database was made and I did confirm that everything is proper there. I can even use the same commands(except for file location) on my windows computer and I have no problem reading and editing it. The PI 0W is headless. After confirming what I could on my windows machine, I transferred it to the pi and I have had issues. At first I was rebooting the Pi and checking, then I decided to let the original crontab run and run the new code through Putty. The original does not use SQLite3 at all so it shouldn't be a problem and shouldn't be causing the error. The callbacks are triggering properly.

 

After a few tries I finally got an error log set up(you can see the remnants of the failed try). It would not log to file in the first attempt.

 

# Buttons for Tyon screen
import sqlite3
import RPi.GPIO as GPIO
import time
import datetime
import os
from datetime import date
from datetime import datetime
import logging
import subprocess


GPIO.setmode(GPIO.BCM)

#Error Logging
#logging.basicConfig(filename='TysonButtonErrorLog.log', encoding='utf-8', level=logging.DEBUG)

#database Connection
con = sqlite3.connect('/home/pi/tyson101/python/examples/TysonDB.db')
cur = con.cursor()
dataDump = [] #A place to dump data recieved for DB
thisdate = [] #A place to store current date for comparison

# Set sleep time
sleepTm = 2

# Set Pins for buttons in GPIO
fb = 12
mb = 16
check = False

#counter
ctd = 120
tmo = 120
pto = 200

def getWeek():
    global dataDump
    global thisdate
    global cur #not sure if these need to be here but tried anyways
    global con
    dataDump.clear() #Clears list for fresh info
    #get last day of data
    try:
        thisdate = [int(datetime.today().year), int(datetime.today().month), int(datetime.today().day)]#Set todays date to compare. first try:(datetime.strptime('%Y')), datetime.strptime('%m'), datetime.strptime("%d")]
        #cur=con.cursor() #This might be a mistake, commented out to check
        cur.execute("SELECT Year, Month, Date, Food, AM, PM FROM Food WHERE Year = ? AND Month = ? ORDER BY -Date", (thisdate[0], thisdate[1]))
        row =  cur.fetchone() #Get one record, where condition above makes it the most recent
        for entry in row:
            dataDump.append(entry) #Append results in my list
        print(str(dataDump)) #**********************************************DEBUG************************************************
    except Exception as Argument:
        f= open("TysonButtonErrorLog.txt", "a")
        f.write(str(Argument))
        f.close()
        logging.error(Argument, exc_info=True)



# Callback for buttons
def fb_callback(fb):  # Food Button
    global ctd
    global tmo
    global dataDump
    global thisdate
    global cur
    global con
    getWeek()
    if ctd == 0:
        try:
            #If date is found, compares date in fields of DB and compares to current date
            if dataDump[0] == thisdate[0] and dataDump[1] == thisdate[1] and dataDump[2] == thisdate[2]:
                if dataDump[3] < 6: #5 is the max, do not add if over.
                    tempDump =  [(dataDump[3] + 1), dataDump[0], dataDump[1], dataDump[2]] #list for the update with the updated field first
                    print(str(tempDump)) #*************************************************DEBUG***************************************
                    #dataDump.insert(0, (dataDump[3] + 1)) #Alternate method
                    sqlUpdate = """UPDATE Food SET Food = ? WHERE Year = ? AND Month = ? AND Date = ?"""
                    cur.execute(sqlUpdate, tempDump)
                    con.commit()
            else:
                f = open("TysonButtonErrorLog.txt", "a")
                f.write(str('Date Missmatch'))
                f.close()
            con.close()
            ctd = tmo
        except Exception as Argument:
            f = open("TysonButtonErrorLog.txt", "a")
            f.write(str(Argument))
            f.close()
            logging.error(Argument, exc_info=True)

 

This is the error message I get. It does actually repeat like that every time. I unfortunately do not know how to solve this. This would be the first time calling the database so I do not know what other thread would be running unless the PI OS happens to be using it and it would not let me create a new thread for my query. I made my cursor and connection global just to be sure it wasn't creating a new object inside the function.

 

SQLite objects created in a thread can only be used in that same thread. The object was created in thread id 3069925600 and this is thread id 3058426976.list index out of rangeSQLite objects created in a thread can only be used in that same thread. The object was created in thread id 3069925600 and this is thread id 3058426976.list index out of rangeSQLite objects created in a thread can only be used in that same thread. The object was created in thread id 3069479136 and this is thread id 3057980512.SQLite objects created in a thread can only be used in that same thread. The object was created in thread id 3069479136 and this is thread id 3057980512.SQLite objects created in a thread can only be used in that same thread. The object was created in thread id 3069479136 and this is thread id 3057980512.SQLite objects created in a thread can only be used in that same thread. The object was created in thread id 3069479136 and this is thread id 3057980512.SQLite objects created in a thread can only be used in that same thread. The object was created in thread id 3069458656 and this is thread id 3057960032.SQLite objects created in a thread can only be used in that same thread. The object was created in thread id 3069458656 and this is thread id 3057960032.SQLite objects created in a thread can only be used in that same thread. The object was created in thread id 3069458656 and this is thread id 3057960032.SQLite objects created in a thread can only be used in that same thread. The object was created in thread id 3069458656 and this is thread id 3057960032.SQLite objects created in a thread can only be used in that same thread. The object was created in thread id 3069458656 and this is thread id 3057960032.SQLite objects created in a thread can only be used in that same thread. The object was created in thread id 3069458656 and this is thread id 3057960032.list index out of rangeSQLite objects created in a thread can only be used in that same thread. The object was created in thread id 3069458656 and this is thread id 3057960032.list index out of range

Any help would be appreciated.


   
Quote
huckOhio
(@huckohio)
Member
Joined: 5 years ago
Posts: 180
 

@madmisha

I am NOT a python expert, but I looked at a program I wrote years ago that used the SQLitye3 DB.  Each function/thread that needed to connect to the database had all the code necessary within the function/thread.  For example, the following code was from a load(self) function in a thread.  There was also a function called table_cell_clicked(self, row, col): that used the exact same code except for the execution command.   

 

BASE_DIR = os.path.dirname(os.path.abspath(__file__))
db_path = os.path.join(BASE_DIR, "RPT_DB")
conn = sqlite3.connect(db_path)
c = conn.cursor()
c.execute("SELECT * FROM TherapyTypes")
.
.
.
.
.
conn.commit()
conn.close()

   
ReplyQuote
MadMisha
(@madmisha)
Member
Joined: 4 years ago
Posts: 340
Topic starter  

@huckohio 

I did just get it to work. I removed the connection and cursor object at the beginning and I included it in my functions, every time I needed it. I'm assuming that it was because it considered the functions separate threads(or it uses separate threads but I didn't think that Python would do that since it reads top down and does one thing at a time). Apparently, me declaring's it at the top opened it and the other calls were not allowed to use that thread. I'm not sure if this is the right way of doing it, but it worked. I would have thought that making an object at the top and calling would have been the correct way.

# Buttons for Tyon screen
import sqlite3
import RPi.GPIO as GPIO
import time
import datetime
import os
from datetime import date
from datetime import datetime, timedelta

GPIO.setmode(GPIO.BCM)

#Lists for use
dataDump = [] #A place to dump data recieved for DB
thisdate = [] #A place to store current date for comparison
newRecord = [0, 0, 0, 0, 0, 0, 0] #Holder for the new record

# Set sleep time
sleepTm = 2

# Set Pins for buttons in GPIO
fb = 12
mb = 16
check = False

#counter
ctd = 120
tmo = 120
pto = 200

def getWeek():
    global dataDump
    global thisdate
    global cur #not sure if these need to be here but tried anyways
    global con
    dataDump.clear() #Clears list for fresh info
    #Get last day of data
    try:
        thisdate = [int(datetime.today().year), int(datetime.today().month), int(datetime.today().day)]#Set todays date to compare.
        con = sqlite3.connect('/home/pi/tyson101/python/examples/TysonDB.db')
        cur = con.cursor()
        cur.execute("SELECT Year, Month, Date, Food, AM, PM FROM Food WHERE Year = ? AND Month = ? ORDER BY -Date", (thisdate[0], thisdate[1]))
        row = cur.fetchone() #Get one record, where condition above makes it the most recent
        for entry in row:
            dataDump.append(entry) #Append results in my list
        con.close()
    except Exception as Argument:
        f= open("TysonButtonErrorLog.txt", "a")
        f.write(str(Argument))
        f.close()

# Callback for buttons
def fb_callback(fb):  # Food Button
    global ctd
    global tmo
    global dataDump
    global thisdate
    global cur
    global con
    if ctd == 0: #If timer had reached 0, this is because the built in debounce did not work. Timer is in loop section.
        try:
            getWeek()
            #If date is found, compares date in fields of DB and compares to current date
            if dataDump[0] == thisdate[0] and dataDump[1] == thisdate[1] and dataDump[2] == thisdate[2]:
                if dataDump[3] < 6: #5 is the max, do not add if over.
                    tempDump =  [(dataDump[3] + 1), dataDump[0], dataDump[1], dataDump[2]] #list for the update with the updated field first
                    con = sqlite3.connect('/home/pi/tyson101/python/examples/TysonDB.db')
                    cur = con.cursor()
                    sqlUpdate = """UPDATE Food SET Food = ? WHERE Year = ? AND Month = ? AND Date = ?"""
                    cur.execute(sqlUpdate, tempDump)
                    con.commit()
            else:
                today = date.today()
                newRecordtemp = [thisdate[1], thisdate[2], thisdate[0], int(today.weekday()), 1, 0, 0]
                con = sqlite3.connect('/home/pi/tyson101/python/examples/TysonDB.db')
                cur = con.cursor()
                sqlInsert = """INSERT INTO Food VALUES (?, ?, ?, ?, ?, ?, ?)"""
                cur.execute(sqlInsert, newRecordtemp)
                con.commit()
            con.close()
            os.system('python3 /home/pi/tyson101/python/examples/Tyson.py')
            ctd = tmo
        except Exception as Argument:
            f = open("TysonButtonErrorLog.txt", "a")
            f.write(str(Argument))
            f.close()

 This is so much cleaner than my original. It is also far easier to fix mistakes later.


   
huckOhio reacted
ReplyQuote