0

quite new to Python and come across a problem that I'm struggling to diagnose.

I am working on a project involving a Tkinter menu and using an ADC connected to a potentiometer (which will hopefully be replaced by a muscle sensor once I've gotten the essential code working). I am using a raspberry Pi and breadboard for this, with my IDE as Thonny.

The imports are:

from time import sleep
import busio
import digitalio
import board
import adafruit_mcp3xxx.mcp3008 as ADC
from adafruit_mcp3xxx.analog_in import AnalogIn
import tkinter as tk
from tkinter import Menu
import easygui
import RPi.GPIO as GPIO

The overall menu and code works until I try to use the Run() function, which uses all of the files and compares AnalogIn to a threshold value previously found. When the Run button is clicked, it comes up with the error:

Exception in Tkinter callback
Traceback (most recent call last):
  File "/usr/lib/python3.9/tkinter/__init__.py", line 1892, in __call__
  File "/home/pi/Documents/NEA_Python/NEA2023.py", line 280, in Run
  File "/usr/local/lib/python3.9/dist-packages/adafruit_mcp3xxx/analog_in.py", line 53, in value
  File "/usr/local/lib/python3.9/dist-packages/adafruit_mcp3xxx/mcp3xxx.py", line 80, in read
  File "/usr/local/lib/python3.9/dist-packages/adafruit_bus_device/spi_device.py", line 93, in __enter__
  File "/usr/local/lib/python3.9/dist-packages/busio.py", line 335, in configure
  File "/usr/local/lib/python3.9/dist-packages/adafruit_platformdetect/board.py", line 650, in any_embedded_linux
  File "/usr/local/lib/python3.9/dist-packages/adafruit_platformdetect/board.py", line 532, in any_raspberry_pi
  File "/usr/local/lib/python3.9/dist-packages/adafruit_platformdetect/board.py", line 205, in _pi_rev_code
  File "/usr/local/lib/python3.9/dist-packages/adafruit_platformdetect/__init__.py", line 42, in get_cpuinfo_field
OSError: [Errno 24] Too many open files: '/proc/cpuinfo'

Run() Function code:

def Run():
    threshold_valid = False
    output_valid = False
   
    #validity checks for all necessary fields
    if threshold_valid == False:
        thres = open('Threshold.txt', 'r')
        threshold = thres.read()
        if threshold == '':
            print("Missing threshold voltage. Please refer to Main Menu/Options/Edit Muscle Data/Find threshold voltage")
        else:
            threshold_valid = True
           
    if output_valid == False:
        output = open('OutputOption.txt', 'r')
        outputOption = output.read()
        if outputOption == '':
            print("Missing output option. Please refer to  Main Menu/Options/Edit Muscle Data/Choose output/  in order to select output")
        elif outputOption == 'notification':
            with open('Message.txt', 'r') as message:
                if message.read() == '':
                    print("Missing message to display. Please refer to  Main Menu/Options/Edit Muscle Data/Choose output/Display message/")
                else:
                    output_valid = True
                    message.close()
        elif outputOption() == 'LED':
            output_valid = True
        else:
            print("Something went wrong. Try deleting stored data at  Main Menu/Options/Edit Muscle Data/Delete Data/  and try again")
   
    while threshold_valid == True and output_valid == True:
                           
        spiBus = busio.SPI(clock=board.SCK, MISO=board.MISO, MOSI=board.MOSI)
        # create the chip select
        chipSelect = digitalio.DigitalInOut(board.D22)
        #creates the object for adc
        adc = ADC.MCP3008(spiBus, chipSelect)
        #creates analogue input channel on ADC's pin 0
        analogueInChan = AnalogIn(adc, ADC.P0)
        instantaneousAIn = analogueInChan.value
       
        if  instantaneousAIn> int(threshold):
            if outputOption == 'LED':
                output_flashLED()
           
            elif outputOption == 'notification':
                output_notification()
               
           
    thres.close()
    output.close()

All of the validity checks for this work fine, but it fails once it reaches the part inside the 'while threshold_valid == True and output_valid == True:' statement.

The menu is a menubar with cascade menus coming off of it. The Tkinter menu code is:

#Root window
root = tk.Tk()
root.title("Main Menu")

#Creates a menubar
menubar = Menu(root, bg = 'powderblue', activebackground = '#84b7c4', tearoff = 0)
root.config(menu = menubar)

#Creates the main menu with the menubar as its parent window
#bg is the natural background colour, activebackground is the colour when the mouse hovers over it
main_menu = Menu(menubar, bg = 'lightcyan', activebackground = 'powderblue', tearoff = 0)

#Adds option to main_menu
main_menu.add_command(
    label = "Instructions",
    command = instructions
)

main_menu.add_command(
    label= "Run",
    command = Run
)

#Adds the main_menu as cascade to the menubar
menubar.add_cascade(
    label = "Options",
    menu = main_menu
)


#Creates menu muscleData_menu with main_menu as parent window
muscleData_menu = Menu(main_menu, tearoff = 0, bg = 'lightcyan', activebackground = 'powderblue')

#Adds option to muscleData_menu
muscleData_menu.add_command(
    label = "Instructions",
    command = instructions
)

muscleData_menu.add_command(
    label = "Find threshold voltage",
    command = findThreshold
)


#Creates menu output_menu with muscleData_menu as parent window
output_menu = Menu(muscleData_menu, tearoff = 0, bg = 'lightcyan', activebackground = 'powderblue')

#Adds option to output_menu
output_menu.add_command(
    label = "Flash LED",
    command = menuoption_flashLED
)

output_menu.add_command(
    label = "Display message",
    command = menuoption_notification
)

#Adds output_menu as cascade within muscleData_menu
muscleData_menu.add_cascade(
    label = "Choose output",
    menu = output_menu
)


#Creates menu deleteData_menu with muscleData_menu as parent window
deleteData_menu = Menu(muscleData_menu, tearoff = 0, bg = 'lightcyan', activebackground = 'powderblue')

#Adds option to deleteData_menu
deleteData_menu.add_command(
    label = "Delete stored threshold voltage",
    command = deleteThreshold
)

deleteData_menu.add_command(
    label = "Delete stored output option",
    command = deleteOutput
)

deleteData_menu.add_command(
    label = "Delete stored notification message",
    command = deleteMessage
)

deleteData_menu.add_command(
    label = "Delete all stored data",
    command = wipeData
)

#adds deleteData_menu as cascade to the muscleData_menu
muscleData_menu.add_cascade(
    label = "Delete stored data",
    menu = deleteData_menu
)

muscleData_menu.add_command(
    label = "Run",
    command = Run
)


#Adds muscleData_menu as cascade within main_menu
main_menu.add_cascade(
    label = "Edit Muscle Data",
    menu = muscleData_menu,
)

#Ends menu program
#root.destroy completely erases root/menu
main_menu.add_command(
    label = "Quit",
    command=root.destroy,
)

#Runs menu continuously until quit, awaiting user inputs
root.mainloop()

The actual menu works fine, the issue resides inside of the Run() function, however it is a Tkinter related issue. As I understand it, the menu works by the root looping continuously in the background whilst allowing other parts of the code to work, so this may be the issue but I'm not sure how to fix it. I have checked and in all instances of me opening the textfiles across the code, I have closed them again directly after. I have changed the ulimit and it continues to show the same error. I couldn't find a working solution in other stackoverflow answers and so believed it was an issue more localised to my exact code, but apologies if this is a repetition.

The full code is in this google doc, if anyone finds it relevant: https://docs.google.com/document/d/1Oj5M6jSTXepXSBm9kjj4o_41AN4IhGcgc63iedZSMdQ/edit?usp=sharing

mar
  • 1
  • 1
  • So you connected from mcp3008 to RPi 4(I'm using) and potentiometer to pin 1 of mcp3008 ? – toyota Supra Feb 13 '23 at 13:46
  • 1
    @toyotaSupra Yes, my wiring was essentially that of this guide: https://cdn-learn.adafruit.com/downloads/pdf/reading-a-analog-in-and-controlling-audio-volume-with-the-raspberry-pi.pdf Page 6, 40-pin Pi – mar Feb 15 '23 at 16:20
  • Can you use PATH library to open file? – toyota Supra Feb 15 '23 at 16:27

2 Answers2

0

Can you limit the number of files that have to be open at the same time?

I was also reading from this thread,

IOError: [Errno 24] Too many open files:

Please have a look , it might help.

0

You need to use a with block to deal with your files, so they actually get closed and you won't run out of file descriptors.

Replace things like

thres = open('Threshold.txt', 'r')
threshold = thres.read()

with

with open('Threshold.txt', 'r') as f:
    threshold = f.read()
AKX
  • 152,115
  • 15
  • 115
  • 172