0

Why can I not access any variables that I create in this class? I get Control has no attribute setTemp whenever I try to access it. If I declare it outside __init__ I also get an error. For whatever reason, I can't grasp how to properly declare variables in a Python class, then later use them in methods.

from tkinter import *
from tkinter import ttk
from tkinter import messagebox
from vivTimer import *
import RPi.GPIO as GPO
import threading
import time
import board
import adafruit_dht

dhtDevice = adafruit_dht.DHT22(board.D4, use_pulseio=False)

class Control(object):
    
    setHumid = 95
    timer = 5000
    
    def __init__(self, master):

        setTemp = StringVar()
        setTemp.set('85')

        #set default max temp and humidity

        master.title('Vivarium Control')
        master.resizable(False, False)
        master.configure(background = '#e6e6e6')

        self.style = ttk.Style()
        self.style.configure('TFrame', background = '#e6e6e6')
        self.style.configure('TButton', background = '#e1d8b9')
        self.style.configure('TLabel', background = '#e6e6e6', font = ('Arial', 11))
        self.style.configure('Header.TLabel', font = ('Arial', 18, 'bold'))

        self.frame_header = ttk.Frame(master)
        self.frame_header.pack()

        self.logo = PhotoImage(file = '115500-200.png')
        ttk.Label(self.frame_header, image = self.logo).grid(row = 0, column = 0, rowspan = 2)
        ttk.Label(self.frame_header, text = 'Vivarium Controller', style = 'Header.TLabel').grid(row = 0, column = 1)
        ttk.Label(self.frame_header, wraplength = 300,
                  text = ("Temperature and Humidity control.                "
                          "Enter maximums for both humidity and temperature.")).grid(row = 1, column = 1, padx = 5, sticky = 'nw')

        self.frame_content = ttk.Frame(master)
        self.frame_content.pack()

        ttk.Label(self.frame_content, text = 'Maximum Temp:').grid(row = 0, column = 0, padx = 5, sticky = 'sw')
        ttk.Label(self.frame_content, text = 'Maximum Humidity:').grid(row = 0, column = 1, padx = 5, sticky = 'sw')

        
        self.setTempL = Label(self.frame_content, textvariable = setTemp).grid(row = 0, column = 3, padx = 5, sticky = 'sw')
        ttk.Label(self.frame_content, text = 'Current Humidity:' + str(self.setHumid)).grid(row = 0, column = 4, padx = 5, sticky = 'sw')


        self.entry_temp = ttk.Entry(self.frame_content, textvariable = setTemp, width = 10, font = ('Arial', 10))
        self.entry_humid = ttk.Entry(self.frame_content, width = 10, font = ('Arial', 10))

        self.entry_temp.grid(row = 1, column = 0, padx = 5)
        self.entry_humid.grid(row = 1, column = 1, padx = 5)

        ttk.Button(self.frame_content, text = 'Save',
                   command = self.save).grid(row = 4, column = 0, padx = 5, pady = 5, sticky = 'e')

    def updateLabels(self):
        
        print('blah')
        
    def createTimer(root):
        print('timer 1 sec')
        readTemp = False
        while readTemp == False:
            try:
                # Print the values to the serial port
                temperature_c = dhtDevice.temperature
                temperature_f = temperature_c * (9 / 5) + 32
                humidity = dhtDevice.humidity
                
                print(
                    "Temp: {:.1f} F / {:.1f} C    Humidity: {}% ".format(
                        temperature_f, temperature_c, humidity
                    )
                )
                readTemp = True
                if(temperature_f > int(Control.setTemp.get())):
                   print('fan on')

            except RuntimeError as error:
                # Errors happen fairly often, DHT's are hard to read, just keep going
                print(error.args[0])
                time.sleep(2.0)
                continue
            except Exception as error:
                dhtDevice.exit()
                raise error

            time.sleep(2.0)
        
        print(Control.timer)
        root.after(Control.timer, Control.createTimer, root)
        #t2 = threading.Thread(target=VivTimer.startTimer(), args=(10,))
        #t2.start()


    def save(self):

        tempT = self.entry_temp.get()
        self.setTemp = tempT
        print(self.setTemp)
        self.setHumid = self.entry_humid.get()
        Control.updateLabels(self)
        
        print('Temp: {}'.format(self.entry_temp.get()))
        print('Humidity: {}'.format(self.entry_humid.get()))
        self.clear()
        messagebox.showinfo(title = 'Vivarium Control', message = 'Conditions saved!')

    def clear(self):
        self.entry_temp.delete(0, 'end')
        self.entry_humid.delete(0, 'end')



def main():            
    
    root = Tk()
    control = Control(root)
    root.after(1000, Control.createTimer, root)
    root.mainloop()
      
if __name__ == "__main__": main()
5
  • setTemp is a local variable, not a class property. Commented Aug 3, 2022 at 22:01
  • Good catch. OP declared it in the wrong scope. Commented Aug 3, 2022 at 22:02
  • Control.save() creates self.setTemp, but that's an instance attribute, not a class attribute. Commented Aug 3, 2022 at 22:03
  • 3
    You wrote setTemp = StringVar() but you needed self.setTemp = StringVar() Commented Aug 3, 2022 at 22:10
  • Thank you. Python is new to me so I was totally missing the self.setTemp part of it. I now know what I need to read up on more to understand. Everything is currently working with the change. Commented Aug 4, 2022 at 14:51

1 Answer 1

1

I think the following modified version of your code will work much better if you undo all the places I commented out your code (and usually put in a replacement below it). This was necessary to make it possible to run the code at all for testing since I don't have your hardware (or the one image file).

You will need to undo them to try it with your hardware.

The two most significant changes I made were turning setTemp into a class instance attribute and modifying createTimer() to make it a proper class method.

from tkinter import *
from tkinter import ttk
from tkinter import messagebox
#from vivTimer import *
#import RPi.GPIO as GPO
import time
#import board
#import adafruit_dht
#
#dhtDevice = adafruit_dht.DHT22(board.D4, use_pulseio=False)

class Control(object):

    setHumid = 95
    timer = 5000

    def __init__(self, master):
        self.setTemp = StringVar()
        self.setTemp.set('85')

        #set default max temp and humidity

        master.title('Vivarium Control')
        master.resizable(False, False)
        master.configure(background = '#e6e6e6')

        self.style = ttk.Style()
        self.style.configure('TFrame', background = '#e6e6e6')
        self.style.configure('TButton', background = '#e1d8b9')
        self.style.configure('TLabel', background = '#e6e6e6', font = ('Arial', 11))
        self.style.configure('Header.TLabel', font = ('Arial', 18, 'bold'))

        self.frame_header = ttk.Frame(master)
        self.frame_header.pack()

#        self.logo = PhotoImage(file = '115500-200.png')
        self.logo = PhotoImage(file = '8-ball.png')
        ttk.Label(self.frame_header, image = self.logo).grid(row = 0, column = 0, rowspan = 2)
        ttk.Label(self.frame_header, text = 'Vivarium Controller', style = 'Header.TLabel').grid(row = 0, column = 1)
        ttk.Label(self.frame_header, wraplength = 300,
                  text = ("Temperature and Humidity control.                "
                          "Enter maximums for both humidity and temperature.")).grid(row = 1, column = 1, padx = 5, sticky = 'nw')

        self.frame_content = ttk.Frame(master)
        self.frame_content.pack()

        ttk.Label(self.frame_content, text = 'Maximum Temp:').grid(row = 0, column = 0, padx = 5, sticky = 'sw')
        ttk.Label(self.frame_content, text = 'Maximum Humidity:').grid(row = 0, column = 1, padx = 5, sticky = 'sw')


        self.setTempL = Label(self.frame_content, textvariable=self.setTemp).grid(row = 0, column = 3, padx = 5, sticky = 'sw')
        ttk.Label(self.frame_content, text = 'Current Humidity:' + str(self.setHumid)).grid(row = 0, column = 4, padx = 5, sticky = 'sw')


        self.entry_temp = ttk.Entry(self.frame_content, textvariable=self.setTemp, width = 10, font = ('Arial', 10))
        self.entry_humid = ttk.Entry(self.frame_content, width = 10, font = ('Arial', 10))

        self.entry_temp.grid(row = 1, column = 0, padx = 5)
        self.entry_humid.grid(row = 1, column = 1, padx = 5)

        ttk.Button(self.frame_content, text = 'Save',
                   command = self.save).grid(row = 4, column = 0, padx = 5, pady = 5, sticky = 'e')

    def updateLabels(self):

        print('blah')

    def createTimer(self, root):
        print('timer 1 sec')
        readTemp = False
        while readTemp == False:
            try:
                # Print the values to the serial port
#                temperature_c = dhtDevice.temperature
                temperature_c = 30
                temperature_f = temperature_c * (9 / 5) + 32
#                humidity = dhtDevice.humidity
                humidity = 20

                print(
                    "Temp: {:.1f} F / {:.1f} C    Humidity: {}% ".format(
                        temperature_f, temperature_c, humidity
                    )
                )
                readTemp = True
                if(temperature_f > int(self.setTemp.get())):
                   print('fan on')

            except RuntimeError as error:
                # Errors happen fairly often, DHT's are hard to read, just keep going
                print(error.args[0])
                time.sleep(2.0)
                continue
            except Exception as error:
#                dhtDevice.exit()
                raise error

            time.sleep(2.0)

        print(Control.timer)
        root.after(Control.timer, self.createTimer, root)

    def save(self):
        tempT = self.entry_temp.get()
        self.setTemp = tempT
        print(self.setTemp)
        self.setHumid = self.entry_humid.get()
        Control.updateLabels(self)

        print('Temp: {}'.format(self.entry_temp.get()))
        print('Humidity: {}'.format(self.entry_humid.get()))
        self.clear()
        messagebox.showinfo(title = 'Vivarium Control', message = 'Conditions saved!')

    def clear(self):
        self.entry_temp.delete(0, 'end')
        self.entry_humid.delete(0, 'end')


def main():
    root = Tk()
    control = Control(root)
    root.after(1000, control.createTimer, root)
    root.mainloop()

if __name__ == "__main__":
    main()

Sign up to request clarification or add additional context in comments.

2 Comments

This is exactly what I needed to get moving forward. There's still a lot of basics I dont fully grasp with Python so I appreciate you helping out and getting me on my way.
It's good to hear my answer helped and was worth the effort it took to make. Besides learning Python, you're also dealing with tkinter which has many of its own idiosyncrasies (and is poorly documented).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.