If_i_only_knew101
Posts: 37
Joined: Mon Jul 19, 2021 12:54 am

combining a .py script into a Tk gui

Mon Aug 02, 2021 7:13 am

hi all,
im a total noob, i trying to combine a voltage monitoring and relay system with a Tk time/date program
im trying to display the .print statements from voltage control.py in clock tab under the time date.
((im having trouble seeing the voltage displayed by terminal and the desktop pi clock)
both programs work just not together
im getting a positioning error...

Code: Select all

import time
from tkinter import *
from tkinter.ttk import *
import datetime
import platform
try:
        import winsound
        type='windows'
except:
        import os
        type='other'

window = Tk()
window.title("Clock")
window.geometry('500x250')
stopwatch_counter_num = 66600
stopwatch_running = False
timer_counter_num = 66600
timer_running = False
VOLTAGE_CONTROL = exec #start voltage control.py so relay control is active.

def value(): #debug highlights this line in yellow then line 179 (value_label.pack(anchor='s') then-
#line 210 value(clock()) #TypeError: value() takes 0 positional arguments but 1 was given (clock is displayed but no voltage values).

    from VOLTAGE_CONTROL import (value)
    value = value_value= value.value.now()    
    value_label.config(text= value)
    value_label.config = value_label.pack
# at this point i had wished to- 1. start voltage control py so relays are working.
# 2. import from voltage control py - as values and display it under the time and date in time/date tab.

def clock():
    date_time = datetime.datetime.now().strftime("%d-%m-%Y %H:%M:%S/%p")
    date,time1 = date_time.split()
    time2,time3 = time1.split('/')
    hour,minutes,seconds =  time2.split(':')
    if int(hour) > 11 and int(hour) < 24:
            time = str(int(hour) - 12) + ':' + minutes + ':' + seconds + ' ' + time3
            
    else:
            time = time2 + ' ' + time3
    time_label.config(text = time)
    date_label.config(text= date)
    time_label.after(1000, clock)

def alarm():
        main_time = datetime.datetime.now().strftime("%H:%M %p")
        alarm_time = get_alarm_time_entry.get()
        alarm_time1,alarm_time2 = alarm_time.split(' ')
        alarm_hour, alarm_minutes = alarm_time1.split(':')
        main_time1,main_time2 = main_time.split(' ')
        main_hour1, main_minutes = main_time1.split(':')
        if main_time2 == 'PM':
                main_hour = str(int(main_hour1) - 12)
        else:
                main_hour = main_hour1
        if int(alarm_hour) == int(main_hour) and int(alarm_minutes) == int(main_minutes) and main_time2 == alarm_time2:
                for i in range(3):
                        alarm_status_label.config(text='Time Is Up')
                        if platform.system() == 'Windows':
                                winsound.Beep(5000,1000)
                        elif platform.system() == 'Darwin':
                                os.system('say Time is Up')
                        elif platform.system() == 'Linux':
                                os.system('beep -f 5000')
                get_alarm_time_entry.config(state='enabled')
                set_alarm_button.config(state='enabled')
                get_alarm_time_entry.delete(0,END)
                alarm_status_label.config(text = '')
        else:
                alarm_status_label.config(text='Alarm Has Started')
                get_alarm_time_entry.config(state='disabled')
                set_alarm_button.config(state='disabled')
        alarm_status_label.after(1000, alarm)

def stopwatch_counter(label):
        def count():
                if stopwatch_running:
                        global stopwatch_counter_num
                        if stopwatch_counter_num==66600:
                                display="Starting..."
                        else:
                                tt = datetime.datetime.fromtimestamp(stopwatch_counter_num) 
                                string = tt.strftime("%H:%M:%S") 
                                display=string 
                        label.config(text=display)
                        label.after(1000, count)
                        stopwatch_counter_num += 1
        count()
        
def stopwatch(work):
         if work == 'start':
                 global stopwatch_running
                 stopwatch_running=True
                 stopwatch_start.config(state='disabled')
                 stopwatch_stop.config(state='enabled')
                 stopwatch_reset.config(state='enabled')
                 stopwatch_counter(stopwatch_label)
         elif work == 'stop':
                 stopwatch_running=False
                 stopwatch_start.config(state='enabled')
                 stopwatch_stop.config(state='disabled')
                 stopwatch_reset.config(state='enabled')
         elif work == 'reset':
                 global stopwatch_counter_num
                 stopwatch_running=False
                 stopwatch_counter_num=66600
                 stopwatch_label.config(text='Stopwatch')
                 stopwatch_start.config(state='enabled')
                 stopwatch_stop.config(state='disabled')
                 stopwatch_reset.config(state='disabled')

def timer_counter(label):
        def count():
                global timer_running
                if timer_running:
                        global timer_counter_num
                        if timer_counter_num==66600:
                            for i in range(3):
                                    display="Time Is Up"
                                    if platform.system() == 'Windows':
                                        winsound.Beep(5000,1000)
                                    elif platform.system() == 'Darwin':
                                        os.system('say Time is Up')
                                    elif platform.system() == 'Linux':
                                        os.system('beep -f 5000')
                            timer_running=False
                            timer('reset')
                        else:
                                tt = datetime.datetime.fromtimestamp(timer_counter_num) 
                                string = tt.strftime("%H:%M:%S") 
                                display=string
                                timer_counter_num -= 1
                        label.config(text=display)
                        label.after(1000, count)
        count()

def timer(work):
         if work == 'start':
                 global timer_running, timer_counter_num
                 timer_running=True
                 if timer_counter_num == 66600:
                         timer_time_str = timer_get_entry.get()
                         hours,minutes,seconds=timer_time_str.split(':')
                         minutes = int(minutes)  + (int(hours) * 60)
                         seconds = int(seconds) + (minutes * 60)
                         timer_counter_num = timer_counter_num + seconds  
                 timer_counter(timer_label)
                 timer_start.config(state='disabled')
                 timer_stop.config(state='enabled')
                 timer_reset.config(state='enabled')
                 timer_get_entry.delete(0,END)
         elif work == 'stop':
                 timer_running=False
                 timer_start.config(state='enabled')
                 timer_stop.config(state='disabled')
                 timer_reset.config(state='enabled')
         elif work == 'reset':
                 timer_running=False
                 timer_counter_num=66600
                 timer_start.config(state='enabled')
                 timer_stop.config(state='disabled')
                 timer_reset.config(state='disabled')
                 timer_get_entry.config(state='enabled')
                 timer_label.config(text = 'Timer')

tabs_control = Notebook(window)
clock_tab = Frame(tabs_control)
alarm_tab = Frame(tabs_control)
stopwatch_tab = Frame(tabs_control)
timer_tab = Frame(tabs_control)
tabs_control.add(clock_tab, text="Clock")
tabs_control.add(alarm_tab, text="Alarm")
tabs_control.add(stopwatch_tab, text='Stopwatch')
tabs_control.add(timer_tab, text='Timer')
tabs_control.pack(expand = 1, fill ="both")
time_label = Label(clock_tab, font = 'calibri 30 bold', foreground = 'black') # changed text size
time_label.pack(anchor='center')
date_label = Label(clock_tab, font = 'calibri 15 bold', foreground = 'black')# changed text size
date_label.pack(anchor='n') #position (top)
value_label = Label(clock_tab, font = 'calibri 25 bold', foreground = 'black') #  clock tab (id prefer using colors from VOLTAGE_CONTROL.py import but increase txt size of it bigger)

value_label.pack(anchor='s') #position (bottom) - error is here i think (debug highlights this line in yellow as well as def value() line22).

get_alarm_time_entry = Entry(alarm_tab, font = 'calibri 15 bold')
get_alarm_time_entry.pack(anchor='center')
alarm_instructions_label = Label(alarm_tab, font = 'calibri 10 bold', text = "Enter Alarm Time. Eg -> 01:30 PM, 01 -> Hour, 30 -> Minutes")
alarm_instructions_label.pack(anchor='s')
set_alarm_button = Button(alarm_tab, text = "Set Alarm", command=alarm)
set_alarm_button.pack(anchor='s')
alarm_status_label = Label(alarm_tab, font = 'calibri 15 bold')
alarm_status_label.pack(anchor='s')
stopwatch_label = Label(stopwatch_tab, font='calibri 40 bold', text='Stopwatch')
stopwatch_label.pack(anchor='center')
stopwatch_start = Button(stopwatch_tab, text='Start', command=lambda:stopwatch('start'))
stopwatch_start.pack(anchor='center')
stopwatch_stop = Button(stopwatch_tab, text='Stop', state='disabled',command=lambda:stopwatch('stop'))
stopwatch_stop.pack(anchor='center')
stopwatch_reset = Button(stopwatch_tab, text='Reset', state='disabled', command=lambda:stopwatch('reset'))
stopwatch_reset.pack(anchor='center')
timer_get_entry = Entry(timer_tab, font='calibiri 15 bold')
timer_get_entry.pack(anchor='center')
timer_instructions_label = Label(timer_tab, font = 'calibri 10 bold', text = "Enter Timer Time. Eg -> 01:30:30, 01 -> Hour, 30 -> Minutes, 30 -> Seconds")
timer_instructions_label.pack(anchor='s')
timer_label = Label(timer_tab, font='calibri 40 bold', text='Timer')
timer_label.pack(anchor='center')
timer_start = Button(timer_tab, text='Start', command=lambda:timer('start'))
timer_start.pack(anchor='center')
timer_stop = Button(timer_tab, text='Stop', state='disabled',command=lambda:timer('stop'))
timer_stop.pack(anchor='center')
timer_reset = Button(timer_tab, text='Reset', state='disabled', command=lambda:timer('reset'))
timer_reset.pack(anchor='center')

value(clock()) #TypeError: value() takes 0 positional arguments but 1 was given (clock is displayed but no voltage values).
#value() (using value() and clock() instead of value(clock()) - volage monitor takovershell and clock interface doesnt appear).
#clock()
window.mainloop()
the python code im trying to interface as part of the Tk gui-

Code: Select all

#!/usr/bin/env python3b
import time
import smbus
import sys
import click
DEVICE_BUS = 1
DEVICE_ADDR = 0x11 #0x12 ( 0x13 , 0x14).
bus = smbus.SMBus(DEVICE_BUS)

from ads1015 import ADS1015
CHANNELS = ['in0/ref', 'in1/ref', 'in2/ref']

# adds colour to print statments when called
fg = lambda text, bold, color: "\33[38;5;" + str(color) + "m" + text + "\33[0m"

#green = 10 
#red = 9
#yellow = 11
#light blue = 190
#light grey = 156
# purple = 165

ads1015 = ADS1015()
ads1015.set_mode('single')
ads1015.set_programmable_gain(2.048)
ads1015.set_sample_rate(1600)

reference = ads1015.get_reference_voltage()

print("Reference voltage: {:6.3f}v \n".format(reference))

try:
    while True:
        click.clear()
        print("")
        for channel in CHANNELS:
            value = ads1015.get_compensated_voltage(channel=channel, reference_voltage=reference)
            print("")
            print(fg(" {}:      {:6.3f} volts".format(channel, value), 'bold', 51))

 
# in0 used to monitor solar volts of hotwater system decidated pannel.
            if channel == "in0/ref":# This will cause relay 3 only to switch when reading channel 0. unless commanded else where.
            
                if value >= 2.000 and value <= 19.000:# voltage range of print solar voltage.
                    print(fg(" HW SOLAR", 'bold', 10))

                elif value <= 1.999:# voltage range of print no solar input.
                    print(fg(" HW NO SOLAR", 'bold', 11)) 

                elif value >= 19.001 and 22.500:# voltage range of print no solar input.
                    print(fg(" HW SOLAR", 'bold', 165)) 
                
                else:
#                    bus.write_byte_data(DEVICE_ADDR, 3, 0xFF)# overvolts trips relay 3 on (relay 3 connected to warning buzzer/audio warning)  
                    print(fg(" WARNING: SOLAR SYSTEM OVERVOLTAGE", 'bold', 9))# print warning and instructions for overvolts to follow.
                    print(fg(" WARNING ISOLATE Pi ADC and SOLAR CB", 'bold', 9))

# in1 usde to monitor main solar bank.
            if channel == "in1/ref":# this will cause relay 2 and 3 only to switch when reading channel 1, unless commanded else where.
                       
                if value >= 2.000 and value <= 17.500:# voltage range of print solar voltage.
                    print(fg(" MAINS:SOLAR", 'bold', 10))
                    
                elif value <= 1.999:# voltage range of print no solar input.
                    print(fg(" MAINS:NO SOLAR", 'bold', 11)) 

                elif value >= 17.501 and 22.500:# voltage range of print no solar input.
                    print(fg(" HW SOLAR", 'bold', 165)) 

                else:
#                    bus.write_byte_data(DEVICE_ADDR, 3, 0xFF)# overvolts trips relay 3 on (relay 3 connected to warning buzzer/audio warning)  
                    print(fg(" WARNING: MAINS SOLAR", 'bold', 9))# print warning and instructions for overvolts to follow.
                    print(fg(" WARNING: SYSTEM OVERVOLTAGE", 'bold',9))
                    print(fg(" WARNING ISOLATE MAIN SOLAR CB", 'bold', 9))
                
# in2 displays battery status.
            if channel == "in2/ref":# this will cause relay 4 only to switch when reading channel 2 unless commanded else where.
 
                if value <= 11.000:# range in battery capacity.
                    bus.write_byte_data(DEVICE_ADDR, 2, 0x00)# ensures hotwater system is off and hasnt latched on by other means. (fail safe to protect batteries from accidental drain).
                    bus.write_byte_data(DEVICE_ADDR, 3, 0x00)# turns off relay 3 audio alarm.
#                   bus.write_byte_data(DEVICE_ADDR, 4, 0xFF)# turns on relay 4 and 300A slave relay (using NC/COM contacts) ON DISCONNECTING BATTERY FROM CIRCUIT.
#                   300A relay not installed (yet to be delivered).
                    print(fg(" SYSTEM WARNING", 'bold', 11))# system warning
                    print(fg(" BATTERY SYSTEM DEAD", 'bold', 9))# system is basically dead.
                    print(fg(" URGENT: RECHARGE NOW", 'bold',9))
                    print(fg(" WARNING: BATTERY DAMAGE WILL OCCURE", 'bold',9))
                    print(fg(" HOTWATER SYSTEM OFF", 'bold',10))# print statue of hotwater system.
#                    bus.write_byte_data(DEVICE_ADDR, 2, 0x00)# turn off relay 2 hotwater.
                    
                elif value >= 11.001 and value <= 11.999:# range in battery capacity
                    bus.write_byte_data(DEVICE_ADDR, 3, 0x00)# turns off relay 3 audio alarm.
                    print(fg(" WARNING", 'bold',11))# print(fg system status batteries below half charge (sla agm batteries dont like deep discharge)
                    print(fg(" BATTERY SYSTEM DYING", 'bold',11))
                    print(fg(" RECHARGE NOW", 'bold',11))
                    print(fg(" HOTWATER OFF", 'bold',10))# print statue of hotwater system.
#                    bus.write_byte_data(DEVICE_ADDR, 2, 0x00)# turn off relay 2 hotwater.
                   
                elif value >= 12.000 and value <= 12.200:# range in battery capacity.
                    print(fg(" WARNING",'bold', 11))# print(fg system status
                    print(fg(" BATTERY SYSTEM LOW",'bold', 11))
#                    bus.write_byte_data(DEVICE_ADDR, 2, 0x00)# turn off relay 2 hotwater.
                    print(fg(" HOTWATER OFF",'bold', 10))# print statue of hotwater system.
                    
                elif value >= 12.201 and value <= 13.000:# range in battery capacity.
#                   print(fg("WARNING", 9))# print(fg system status
                    print(fg(" SYSTEM ON BATTERY",'bold', 156))
                    print(fg(" HOTWATER OFF",'bold', 10))# print statue of hotwater system.
#                    bus.write_byte_data(DEVICE_ADDR, 2, 0x00)# turn off relay 2 hotwater.
                    
                elif value >= 13.001 and value <= 13.250:# range for bulk mode charging
                    print(fg(" CHARGING SYSTEM BULK",'bold', 15))# print(fg system status
                    print(fg(" HOTWATER OFF", 'bold', 45))
                    
                elif value >= 13.251 and value <= 13.500:# range for bulk mode charging
                    print(fg(" CHARGING SYSTEM BULK",'bold', 190))# print(fg system status
#                    bus.write_byte_data(DEVICE_ADDR, 2, 0xFF)# turn on relay 2 hotwater.
                    print(fg(" HOTWATER ON",'bold', 9))# print status of hotwater system.

                elif value >= 13.501 and value <= 13.800:# range of float mode
                    print(fg(" CHARGING SYSTEM FLOAT",'bold', 165)) 
#                    bus.write_byte_data(DEVICE_ADDR, 2, 0xFF)# turn on relay 2 hotwater.
                    print(fg(" HOTWATER ON",'bold', 9))# print status of hotwater system.
  
                elif value >= 13.801 and value <= 14.500:# range of absorbsion mode
                    print(fg(" CHARGING SYSTEM ABSORBSION",'bold', 99))
#                    bus.write_byte_data(DEVICE_ADDR, 2, 0xFF)# turn on relay 2 hotwater.
                    print(fg(" HOTWATER ON",'bold', 9))# print status of hotwater system.
  
                elif value >= 14.501 and value <= 15.500:# calcium mode thresholds 15.500v restores full battery capacity in heavily discharged batteries
#                   (not calcified or sulphated sla's which require aditional venting and full 16v charge)
                    print(fg(" CHARGING SYSTEM CALCIUM MODE", 'bold', 159))
                    print(fg(" WARNING CALCIUM MODE",'bold', 9))
#                    bus.write_byte_data(DEVICE_ADDR, 2, 0x00)# switches off relay 2 hotwater (system may be in fault or calcium mode).
                    print(fg(" HOTWATER OFF", 'bold', 10))

                elif value >= 15.501 and value <= 16.000:# voltage range to trip following code.
#                    bus.write_byte_data(DEVICE_ADDR, 4, 0xFF) # relay 4 option to isolate batteries above 15.501v.
                    print(fg(" CALCIIUM MODE"',bold',9)) 
                    print(fg(" WARNING HYDROGEN PRESSURE",'bold', 9))
                    print(fg(" CHECK BATTERIES",'bold', 9))
#                    bus.write_byte_data(DEVICE_ADDR, 2, 0x00)# switches off relay 2 hotwater (system may be in fault or calcium mode).
                    print(fg(" HOTWATER OFF", 'bold', 10))
                 
                else: #value >= 16.001v trips following code.
                    print(fg(" in2 WARNING: OVERVOLTAGE",'bold',9))# print(fg warning
                    print(fg(" FAULT IN CHARGING SYSTEM",'bold', 9))
                    print(fg(" ISOLATE CHARGING & SOLAR CBs",'bold', 9))
#                    bus.write_byte_data(DEVICE_ADDR, 4, 0xFF) # turns on relay 4 and isolates batteries from overvoltage faults <+16v, 
#                    bus.write_byte_data(DEVICE_ADDR, 2, 0x00)# switches off relay 2 hotwater (system may be in fault or calcium mode).
                    print(fg(" HOTWATER OFF",'bold', 10))
#                    bus.write_byte_data(DEVICE_ADDR, 3, 0xFF)# audio warning of fault or calcium mode
                    time.sleep(0.200)# time delay on warning buzzer.
#                    bus.write_byte_data(DEVICE_ADDR, 3, 0x00)# turns off relay 3 audio alarm.


        print("")
#        click.clear()
        time.sleep(1.000)

except KeyboardInterrupt:
     pass
does anyone know what im missing apart from a brain and a life? :D
thankyou.

scotty101
Posts: 4282
Joined: Fri Jun 08, 2012 6:03 pm

Re: combining a .py script into a Tk gui

Mon Aug 02, 2021 7:53 am

Your voltage reading code is the problem. It is one large while loop which will never end.

To make this compatible with tkinter, convert that code in to a function (or class) which will return the value when the function (or method) is called. This function should read the voltage once and return that value.

As it stands this "from VOLTAGE_CONTROL import (value)", isn't valid python. You need to import the library and call functions from it not try to import individual values.

Once you have your voltage reading code working as a function that reads the voltage, sets any outputs and returns the value, you should use the tkinter .after method to schedule the function to be called periodically, say once a second to tie in with your time.sleep(1.00) that you have at the moment.

I have no idea what you are trying to do with "VOLTAGE_CONTROL = exec", again not valid python code.

Your line 210 error "value(clock())" is occurring because you are passing the returned value of clock (which will be None) to the value function which isn't expecting to receive any arguments.
Electronic and Computer Engineer
Pi Interests: Home Automation, IOT, Python and Tkinter

If_i_only_knew101
Posts: 37
Joined: Mon Jul 19, 2021 12:54 am

Re: combining a .py script into a Tk gui

Tue Aug 03, 2021 3:49 am

ok i went back to raw basics and started from scratch.

Code: Select all

from tkinter import Tk
from tkinter.ttk import *
#import time as t

window = Tk()
window.title("Clock")
window.geometry('400x400')
window.configure(bg="black")
window.resizable(False, False)


from ads1015 import ADS1015
CHANNELS = ['in0/ref', 'in1/ref', 'in2/ref']

ads1015 = ADS1015()
ads1015.set_mode('single')
ads1015.set_programmable_gain(2.048)
ads1015.set_sample_rate(1600)

reference = ads1015.get_reference_voltage()
print("Reference voltage: {:6.3f}v \n".format(reference))

def volts():# convert the .py by adding definition of function group.
    try:
        while True:
            for channel in CHANNELS:
                value = ads1015.get_compensated_voltage(channel=channel, reference_voltage=reference)

#                print("{}: {:6.3f}v".format(channel, value)) #old code print().

#                so i tryed following (getting a eof error at ) in window.main loop()) 
#                i = ("{}: {:6.3f}v".format(channel, value))# this makes the print() line 34 into value i.
#                print(i)# the definition is to print i which is print("{}: {:6.3f}v".format(channel, value)) old code print to display.
#                current_volts = i
                
                current_volts = ('{}: {:6.3f}v'.format(channel, value))# current_volts("{}: {:6.3f}v".format(channel, value))
                volts_label.config(text = current_volts)# config saves i as text in label form for positioning
                volts_label.after(1000, current_volts)# updates config every second.
                volts_label()# prints i which is the print calculated value.

#                t.time(1.000) time pause # as volts_lable.after and config should do similar.
                
                volts_label = Label(window, bg="black", fg="white", font = ("Times", 15, 'bold'), relief='flat')
                volts_label.place(x = 15, y = 5)

        volts()
        window.mainloop()
        
#======= shell error =========
#    window.mainloop()  SyntaxError: unexpected EOF while parsing.
#                    ^
no matter what i try im getting a EOF error. i dont know how to stop the definition function or even if thats the problem...
can anyone spare the time to step me through the above where needed, as simple as possible, (examples is always good).
knowing how this gui works means i can add and edit it for whatever my system requires in automation now and future and tinker where needed...
thankyou.

scotty101
Posts: 4282
Joined: Fri Jun 08, 2012 6:03 pm

Re: combining a .py script into a Tk gui

Tue Aug 03, 2021 1:01 pm

EOF errors usually suggest you've missed a bracket or haven't closed some other type of parenthesis.

The below code is untested but is potentially closer to what I believe you are looking for

Code: Select all

from tkinter import Tk
from tkinter.ttk import *
from ads1015 import ADS1015

def updateVolts():

   #Iterate over the channels and labels to update them in turn.
    for channel, label in zip(CHANNELS,labels):
        value = ads1015.get_compensated_voltage(channel=channel, reference_voltage=reference)
        current_volts = ('{}: {:6.3f}v'.format(channel, value))
        label.config(text = current_volts)
    #Wait 1 second before updating again
    window.after(1000,updateVolts)


CHANNELS = ['in0/ref', 'in1/ref', 'in2/ref']
ads1015 = ADS1015()
ads1015.set_mode('single')
ads1015.set_programmable_gain(2.048)
ads1015.set_sample_rate(1600)
reference = ads1015.get_reference_voltage()
                
window = Tk()
window.title("Voltage Display")
window.geometry('400x400')
window.configure(bg="black")
window.resizable(False, False)    

#You have three channels to read so you need 3 labels to show the voltage values
volts_label1 = Label(window, bg="black", fg="white", font = ("Times", 15, 'bold'), relief='flat')
volts_label.grid()
volts_label2 = Label(window, bg="black", fg="white", font = ("Times", 15, 'bold'), relief='flat')
volts_label2.grid()
volts_label3 = Label(window, bg="black", fg="white", font = ("Times", 15, 'bold'), relief='flat')
volts_label3.grid()
labels = [volts_label1, volts_label2, volts_label3]

window.after_idle(updateVolts) #Call the updateVolts function after the gui has loaded
window.mainloop()

1. Don't use while loops and don't use time.sleep with tkinter. These will block the GUI from updating
2. Don't redraw labels each time you want to change their value, just update the text.
3. Never ever put mainloop inside a while loop. Any code after mainloop (including the loop that it is contained inside) won't be executed until after the GUI is closed
4. Use the .after and .after_idle to schedule a callback function to update values periodically.
Electronic and Computer Engineer
Pi Interests: Home Automation, IOT, Python and Tkinter

If_i_only_knew101
Posts: 37
Joined: Mon Jul 19, 2021 12:54 am

Re: combining a .py script into a Tk gui

Tue Aug 03, 2021 8:13 pm

scotty101 wrote:
Tue Aug 03, 2021 1:01 pm
EOF errors usually suggest you've missed a bracket or haven't closed some other type of parenthesis.

The below code is untested but is potentially closer to what I believe you are looking for

Code: Select all

from tkinter import Tk
from tkinter.ttk import *
from ads1015 import ADS1015

def updateVolts():

   #Iterate over the channels and labels to update them in turn.
    for channel, label in zip(CHANNELS,labels):
        value = ads1015.get_compensated_voltage(channel=channel, reference_voltage=reference)
        current_volts = ('{}: {:6.3f}v'.format(channel, value))
        label.config(text = current_volts)
    #Wait 1 second before updating again
    window.after(1000,updateVolts)


CHANNELS = ['in0/ref', 'in1/ref', 'in2/ref']
ads1015 = ADS1015()
ads1015.set_mode('single')
ads1015.set_programmable_gain(2.048)
ads1015.set_sample_rate(1600)
reference = ads1015.get_reference_voltage()
                
window = Tk()
window.title("Voltage Display")
window.geometry('400x400')
window.configure(bg="black")
window.resizable(False, False)    

#You have three channels to read so you need 3 labels to show the voltage values
volts_label1 = Label(window, bg="black", fg="white", font = ("Times", 15, 'bold'), relief='flat')
volts_label.grid()
volts_label2 = Label(window, bg="black", fg="white", font = ("Times", 15, 'bold'), relief='flat')
volts_label2.grid()
volts_label3 = Label(window, bg="black", fg="white", font = ("Times", 15, 'bold'), relief='flat')
volts_label3.grid()
labels = [volts_label1, volts_label2, volts_label3]

window.after_idle(updateVolts) #Call the updateVolts function after the gui has loaded
window.mainloop()

1. Don't use while loops and don't use time.sleep with tkinter. These will block the GUI from updating
2. Don't redraw labels each time you want to change their value, just update the text.
3. Never ever put mainloop inside a while loop. Any code after mainloop (including the loop that it is contained inside) won't be executed until after the GUI is closed
4. Use the .after and .after_idle to schedule a callback function to update values periodically.
ok thankyou im beginning to see why its structured the way it is. however
im getting the following errors-

Code: Select all

 Traceback (most recent call last):
  File "/home/pi/Desktop/forum fix gui.py", line 30, in <module>
    volts_label1 = Label(window, bg="black", fg="white", font = ("Times", 15, 'bold'), relief='flat')
  File "/usr/lib/python3.7/tkinter/ttk.py", line 761, in __init__
    Widget.__init__(self, master, "ttk::label", kw)
  File "/usr/lib/python3.7/tkinter/ttk.py", line 559, in __init__
    tkinter.Widget.__init__(self, master, widgetname, kw=kw)
  File "/usr/lib/python3.7/tkinter/__init__.py", line 2299, in __init__
    (widgetName, self._w) + extra + self._options(cnf))
_tkinter.TclError: unknown option "-bg" 
is line 761, 559, 2299 is it conflicting with the ttk program, sorry as a noob i dont know anything, but i am learning..

edit-

Code: Select all

window = Tk()
window.title("Voltage Display")
window.geometry('400x400')
window.configure(bg="black")
window.resizable(False, False)    
bg is defined in the configure and appears in every error. this line has worked in all the clock programs ive entered but not accepted now. why hasnt it been defined here?

scotty101
Posts: 4282
Joined: Fri Jun 08, 2012 6:03 pm

Re: combining a .py script into a Tk gui

Wed Aug 04, 2021 7:51 am

What you're seeing is a consequence of your use of from tkinter.ttk import *.
ttk.Labels don't have a bg or fg property, they do however have a background and foreground.

Simple way to fix it is to use the normal tk Label. Note that in the below code, I explicitly import the Label from tk.

Code: Select all

from tkinter import Tk, Label
#from tkinter.ttk import *
#from ads1015 import ADS1015

def updateVolts():

   #Iterate over the channels and labels to update them in turn.
    for channel, label in zip(CHANNELS,labels):
        #value = ads1015.get_compensated_voltage(channel=channel, reference_voltage=reference)
        value = 5.5
        current_volts = ('{}: {:6.3f}v'.format(channel, value))
        label.config(text = current_volts)
    #Wait 1 second before updating again
    window.after(1000,updateVolts)


CHANNELS = ['in0/ref', 'in1/ref', 'in2/ref']
#ads1015 = ADS1015()
#ads1015.set_mode('single')
#ads1015.set_programmable_gain(2.048)
#ads1015.set_sample_rate(1600)
#reference = ads1015.get_reference_voltage()
                
window = Tk()
window.title("Voltage Display")
window.geometry('400x400')
window.configure(bg="black")
window.resizable(False, False)    

#You have three channels to read so you need 3 labels to show the voltage values
volts_label1 = Label(window, bg="black", fg="white", font = ("Times", 15, 'bold'), relief='flat')
volts_label1.grid()
volts_label2 = Label(window, bg="black", fg="white", font = ("Times", 15, 'bold'), relief='flat')
volts_label2.grid()
volts_label3 = Label(window, bg="black", fg="white", font = ("Times", 15, 'bold'), relief='flat')
volts_label3.grid()
labels = [volts_label1, volts_label2, volts_label3]

window.after_idle(updateVolts) #Call the updateVolts function after the gui has loaded
window.mainloop()

Uncomment the ads1015 stuff (I had to comment it out since I don't have one)
Electronic and Computer Engineer
Pi Interests: Home Automation, IOT, Python and Tkinter

If_i_only_knew101
Posts: 37
Joined: Mon Jul 19, 2021 12:54 am

Re: combining a .py script into a Tk gui

Wed Aug 04, 2021 2:44 pm

i got everything together, clock, alarm, volts, its awesome i can see everything.
but im getting a error... (i hashed out ads import...)

Code: Select all

from tkinter import Tk
from tkinter.ttk import *
import datetime        
import click
import time
import sys

import smbus
DEVICE_BUS = 1
DEVICE_ADDR = 0x11 #0x12 ( 0x13 , 0x14).
bus = smbus.SMBus(DEVICE_BUS)

#from ads1015 import ADS1015
#ads1015 = ADS1015()
#ads1015.set_mode('single')
#ads1015.set_programmable_gain(2.048)
#ads1015.set_sample_rate(1600)
#reference = ads1015.get_reference_voltage()            
#CHANNELS = ['in0/ref', 'in1/ref', 'in2/ref']

import platform
try:
        import winsound
        type='windows'
except:
        import os
        type='other'

window = Tk()
window.title("Clock")
window.geometry('450x350')
window.resizable(True, True)    

def clock():
    date_time = datetime.datetime.now().strftime("%d-%m-%Y %H:%M:%S/%p")
    date,time1 = date_time.split()
    time2,time3 = time1.split('/')
    hour,minutes,seconds =  time2.split(':')
    if int(hour) > 11 and int(hour) < 24:
            time = str(int(hour) - 12) + ':' + minutes + ':' + seconds + ' ' + time3
    else:
            time = time2 + ' ' + time3
    time_label.config(text = time)
    date_label.config(text= date)
    time_label.after(1000, clock)

def alarm():
        main_time = datetime.datetime.now().strftime("%H:%M %p")
        alarm_time = get_alarm_time_entry.get()
        alarm_time1,alarm_time2 = alarm_time.split(' ')
        alarm_hour, alarm_minutes = alarm_time1.split(':')
        main_time1,main_time2 = main_time.split(' ')
        main_hour1, main_minutes = main_time1.split(':')
        if main_time2 == 'PM':
                main_hour = str(int(main_hour1) - 12)
        else:
                main_hour = main_hour1
        if int(alarm_hour) == int(main_hour) and int(alarm_minutes) == int(main_minutes) and main_time2 == alarm_time2:
                for i in range(3):
                        alarm_status_label.config(text='Time Is Up')
                        if platform.system() == 'Windows':
                                winsound.Beep(5000,1000)
                        elif platform.system() == 'Darwin':
                                os.system('say Time is Up')
                        elif platform.system() == 'Linux':
                                os.system('beep -f 5000')
                get_alarm_time_entry.config(state='enabled')
                set_alarm_button.config(state='enabled')
                get_alarm_time_entry.delete(0,END)
                alarm_status_label.config(text = '')
        else:
                alarm_status_label.config(text='Alarm Has Started')
                get_alarm_time_entry.config(state='disabled')
                set_alarm_button.config(state='disabled')
        alarm_status_label.after(1000, alarm)

def updateVolts():
   #Iterate over the channels and labels to update them in turn.
    for channel, label in zip(CHANNELS,labels):
        value = ads1015.get_compensated_voltage(channel=channel, reference_voltage=reference)
        current_volts = ('{}:       {:6.3f}v'.format(channel, value))
        label.config(text = current_volts)
    #Wait 1 second before updating again
    window.after(1000,updateVolts) 

# in0 used to monitor solar volts of hotwater system.  not sure if script is functioning untill input active
def updateSolar():
    for channel in CHANNELS:
        value = ads1015.get_compensated_voltage(channel=channel, reference_voltage=reference)
        if channel == 'in0/ref':
            
            if True:
                if value >= 2.000 and value <= 19.000:# voltage range of print solar voltage.
                   current_value = 'HW SOLAR'

                elif value <= 1.999:# voltage range of print no solar input.
                    current_value = 'HW NO SOLAR'
            
                elif value >= 19.001 and  22.500:# voltage range of print no solar input.
                    current_value = 'HW SOLAR'
            
                else:
                    current_value = 'WARNING: SOLAR SYSTEM OVERVOLTAGE'# print warning
            
                solar_label.config(text = current_value)
            window.after(1000, updateSolar)

# in1 usde to monitor main solar bank.      not sure if script is functioning untill input active
def updateMain():
    for channel in CHANNELS:
        value = ads1015.get_compensated_voltage(channel=channel, reference_voltage=reference)
        if channel == 'in1/ref':
            if True:
                
                if value >= 2.000 and value <= 17.500:# voltage range of print solar voltage.
                    main_value = 'MAINS:SOLAR'
                    
                elif value <= 1.999:# voltage range of print no solar input.
                    main_value = 'MAINS:NO SOLAR' 

                elif value >= 17.501 and 22.500:# voltage range of print no solar input.
                    main_value = 'MAINS SOLAR' 

                else:
                    main_value = 'WARNING: MAINS SOLAR OVERVOLTAGE'
                main_label.config(text = main_value)
            window.after(1000, updateSolar)

# in2 displays battery status.
###### known problem below- battery is over 13v and window message says system dead recharge or bury now
def updateBattery():
    for channel in CHANNELS:
        value = ads1015.get_compensated_voltage(channel=channel, reference_voltage=reference)
        if channel == 'in1/ref':
            if True:
                if value <= 11.000:# range in battery capacity.
                    battery_value = 'SYSTEM DEAD RECHARGE OR BURY NOW'# code stuck here instead of line 169 elif value >= 13.501 and value <= 13.800: 
                    data_value = 'HOTWATER SYSTEM off'
#                    bus.write_byte_data(DEVICE_ADDR, 2, 0x00)# ensures hotwater system is off and hasnt latched on by other means.
#                    bus.write_byte_data(DEVICE_ADDR, 3, 0x00)# turns off relay 3 audio alarm.
#                    bus.write_byte_data(DEVICE_ADDR, 4, 0xFF)# turns on relay 4 and 300A slave relay (using NC/COM contacts) ON DISCONNECTING BATTERY FROM CIRCUIT.
#                    300A relay not installed (yet to be delivered).
             
            elif value >= 11.001 and value <= 11.999:# range in battery capacity
                    battery_value = 'SYSTEM DYING RECHARGE NOW'
                    data_value = '  '
#                    bus.write_byte_data(DEVICE_ADDR, 3, 0x00)# turns off relay audio warning
#                    bus.write_byte_data(DEVICE_ADDR, 2, 0x00)# turn off relay 2 hotwater.
                   
            elif value >= 12.000 and value <= 12.200:# range in battery capacity.
                    battery_value = 'SYSTEM LOW RECHARGE NOW'
                    data_value = 'HOTWATER SYSTEM  off'
#                    bus.write_byte_data(DEVICE_ADDR, 2, 0x00)# turn off relay 2 hotwater.
                    
            elif value >= 12.201 and value <= 13.000:# range in battery capacity.
                    battery_value =  'SYSTEM ON BATTERY'
                    data_value = 'HOTWATER SYSTEM  off'
#                    bus.write_byte_data(DEVICE_ADDR, 2, 0x00)# turn off relay 2 hotwater.
                    
            elif value >= 13.001 and value <= 13.250:# range for bulk mode charging
                    battery_value =  'SYSTEM BULK'
                    data_value = 'HOTWATER SYSTEM  off'
                    
            elif value >= 13.251 and value <= 13.500:# range for bulk mode charging
                    battery_value =  'CHARGING SYSTEM BULK'
                    data_value = 'HOTWATER SYSTEM  on'
#                    bus.write_byte_data(DEVICE_ADDR, 2, 0xFF)# turn on relay 2 hotwater.

            elif value >= 13.501 and value <= 13.800:# range of float mode
                    battery_value = 'CHARGING SYSTEM FLOAT'
                    data_value = 'HOTWATER SYSTEM  on'
#                    bus.write_byte_data(DEVICE_ADDR, 2, 0xFF)# turn on relay 2 hotwater.
  
            elif value >= 13.801 and value <= 14.500:# range of absorbsion mode
                    battery_value = 'CHARGING SYSTEM ABSORBSION'
                    data_value = 'HOTWATER SYSTEM  on'
#                    bus.write_byte_data(DEVICE_ADDR, 2, 0xFF)# turn on relay 2 hotwater.
  
            elif value >= 14.501 and value <= 15.500:# calcium mode thresholds 15.500v restores full battery capacity in heavily discharged batteries
#                   (not calcified or sulphated sla's which require aditional venting and full 16v charge)
                    battery_value = 'CHARGING SYSTEM CALCIUM MODE'
                    data_value = 'HOTWATER SYSTEM  off'
#                    bus.write_byte_data(DEVICE_ADDR, 2, 0x00)# switches off relay 2 hotwater (system may be in fault or calcium mode).

            elif value >= 15.501 and value <= 16.000:# voltage range to trip following code.
#                    bus.write_byte_data(DEVICE_ADDR, 4, 0xFF) # relay 4 option to isolate batteries above 15.501v.
                    battery_value = 'SYSTEMS WARNING: CALCIIUM MODE'
                    data_value = 'TRIP SYSTEM NOW'
#                    bus.write_byte_data(DEVICE_ADDR, 2, 0x00)# switches off relay 2 hotwater (system may be in fault or calcium mode).
                 
            else: #value >= 16.001v trips following code.
                    battery_value = 'SYSTEMS WARNING:'
                    data_value = 'OVERVOLTAGE FAULT <16v'
#                    bus.write_byte_data(DEVICE_ADDR, 4, 0xFF) # turns on relay 4 and isolates batteries from overvoltage faults <+16v, 
#                    bus.write_byte_data(DEVICE_ADDR, 2, 0x00)# switches off relay 2 hotwater (system may be in fault or calcium mode).
#                    bus.write_byte_data(DEVICE_ADDR, 3, 0xFF)# audio warning of fault or calcium mode
#                    bus.write_byte_data(DEVICE_ADDR, 3, 0x00)# turns off relay 3 audio alarm.
                    
            battery_label.config(text = battery_value)
            data_label.config(text = data_value)
                
            window.after(1000, updateBattery)

tabs_control = Notebook(window)
clock_tab = Frame(tabs_control)
alarm_tab = Frame(tabs_control)
systems_tab = Frame(tabs_control)
power_tab = Frame(tabs_control)
emergency_tab = Frame(tabs_control)
tabs_control.add(clock_tab, text='clock')
tabs_control.add(alarm_tab, text='alarm')
tabs_control.add(systems_tab, text='systems')
tabs_control.add(power_tab, text='battery')
tabs_control.add(emergency_tab, text ='emergency power')
tabs_control.pack(expand = 1, fill ="both")
date_label = Label(clock_tab, font = 'calibri 20 bold', foreground = 'dark grey')
date_label.pack(anchor='n') #position (top)
time_label = Label(clock_tab, font = 'calibri 36 bold', foreground = 'black') # added module here
time_label.pack(anchor='center')
volts_label1 = Label(clock_tab, font = 'Times 25 bold', foreground='dark orange')
volts_label1.pack(anchor='s')
volts_label2 = Label(clock_tab, font = 'Times 25 bold', foreground='dark violet')
volts_label2.pack(anchor='s')
volts_label3 = Label(clock_tab, font = 'Times 25 bold', foreground='dark blue')
volts_label3.pack(anchor='s')
labels = [volts_label1, volts_label2, volts_label3]
get_alarm_time_entry = Entry(alarm_tab, font = 'calibri 15 bold')
get_alarm_time_entry.pack(anchor='center')
alarm_instructions_label = Label(alarm_tab, font = 'calibri 12 bold', text = "Enter Alarm Time. Eg -> 01:30 PM, 01 -> Hour, 30 -> Minutes")
alarm_instructions_label.pack(anchor='s')
set_alarm_button = Button(alarm_tab, text = "Set Alarm", command=alarm)
set_alarm_button.pack(anchor='s')
alarm_status_label = Label(alarm_tab, font = 'calibri 15 bold')
alarm_status_label.pack(anchor='s')

solar_label = Label(systems_tab, font = 'calibri 15 bold', foreground = 'orange')
solar_label.pack(anchor='n') #position
main_label = Label(systems_tab, font = 'calibri 15 bold', foreground = 'dark violet')
main_label.pack(anchor='center') #position
battery_label = Label(systems_tab, font = 'calibri 15 bold', foreground = 'dark blue')
battery_label.pack(anchor='n') #position
data_label = Label(systems_tab, font = 'calibri 15 bold', foreground = 'dark blue')
data_label.pack(anchor='s') #position

##################  still to do  #######################
#power_label = Label(battery_tab, font = 'calibri 31 bold', foreground = 'black') # added module here
#power_label.pack(anchor='center')
#emergency_label = Label(emergency_tab, font = 'calibri 31 bold', foreground = 'black') # added module here
#emergency_label.pack(anchor='center')
#emergency_shut_down = Button(emergency_tab, text='Emergency Shut Down', state='disabled',command=lambda:emergency('stop'))
#emergency_shut_down.pack(anchor='center')
#emergency_reset = Button(emergency_tab, text='Reset', state='enabled',command=lambda:emergency('reset'))
#emergency_reset.pack(anchor='center')
#emergency_over_ride = Button(emergency_tab, text='Emergency mode', state='disabled', command=lambda:stopwatch('reset'))
#emergency_over_ride_reset.pack(anchor='center')
##########################################################

window.after_idle(updateVolts) #Call the updateVolts function after the gui has loaded
window.after_idle(updateSolar)
window.after_idle(updateMain)
window.after_idle(updateBattery)
clock()
window.mainloop()
in2 prints 13.6 volts so all good there
however its printing line 137

Code: Select all

                 if value <= 11.000:# range in battery capacity.
                    battery_value = 'SYSTEM DEAD RECHARGE OR BURY NOW'# code stuck here instead of line 169 elif value >= 13.501 and value <= 13.800: 
                    data_value = 'HOTWATER SYSTEM off'   
where it should print line 169

Code: Select all

            elif value >= 13.501 and value <= 13.800:# range of float mode
                    battery_value = 'CHARGING SYSTEM FLOAT'
did i do the definition update in's right"
i cant tell if in0 or in1 print functions are working until morning , i think there not working either
(stuck on first if values like in2).
can someone take a look please?
thankyou

User avatar
Paeryn
Posts: 3347
Joined: Wed Nov 23, 2011 1:10 am
Location: Sheffield, England

Re: combining a .py script into a Tk gui

Wed Aug 04, 2021 6:41 pm

If_i_only_knew101 wrote:
Wed Aug 04, 2021 2:44 pm
in2 prints 13.6 volts so all good there
however its printing line 137

Code: Select all

                 if value <= 11.000:# range in battery capacity.
                    battery_value = 'SYSTEM DEAD RECHARGE OR BURY NOW'# code stuck here instead of line 169 elif value >= 13.501 and value <= 13.800: 
                    data_value = 'HOTWATER SYSTEM off'   
where it should print line 169

Code: Select all

            elif value >= 13.501 and value <= 13.800:# range of float mode
                    battery_value = 'CHARGING SYSTEM FLOAT'
did i do the definition update in's right"
i cant tell if in0 or in1 print functions are working until morning , i think there not working either
(stuck on first if values like in2).
can someone take a look please?
thankyou
In the section of code where I think this is :-

Code: Select all

# in2 displays battery status.
###### known problem below- battery is over 13v and window message says system dead recharge or bury now
def updateBattery():
    for channel in CHANNELS:
        value = ads1015.get_compensated_voltage(channel=channel, reference_voltage=reference)
        if channel == 'in1/ref':
            if True:
                if value <= 11.000:# range in battery capacity.
                    battery_value = 'SYSTEM DEAD RECHARGE OR BURY NOW'# code stuck here instead of line 169 elif value >= 13.501 and value <= 13.800: 
the comment says in2 for the battery but the outer if statement in the function reads

Code: Select all

if channel == 'in1/ref':
So it is printing based on what value in1 was at, not the value of in2.
She who travels light — forgot something.
Please note that my name doesn't start with the @ character so can people please stop writing it as if it does!

If_i_only_knew101
Posts: 37
Joined: Mon Jul 19, 2021 12:54 am

Re: combining a .py script into a Tk gui

Wed Aug 04, 2021 10:54 pm

I corrected that, elif and windows.after indents and it's working. I haven't tried relays yet so fingers crossed.
Thankyou for finding it I'm going code blind...

If_i_only_knew101
Posts: 37
Joined: Mon Jul 19, 2021 12:54 am

Re: combining a .py script into a Tk gui

Sun Aug 08, 2021 1:51 am

hi im not sure about the cpu temperature print function i cant seem to get
cpu xx.xx *C to print and the new part temperature sensor i just dont know...

Code: Select all

import datetime

from gpiozero import CPUTemperature

from w1thermsensor import W1ThermSensor# temp one wire pi config enabled.
#temperature sensor data to pi pin 3, Vin 3.3v pin 1, ground to pin 9.

import smbus
DEVICE_BUS = 1
DEVICE_ADDR = 0x11#, 0x12#, 0x13#, 0x14
bus = smbus.SMBus(DEVICE_BUS)
from ads1015 import ADS1015
ads1015 = ADS1015()
ads1015.set_mode('single')
ads1015.set_programmable_gain(2.048)
ads1015.set_sample_rate(1600)
reference = ads1015.get_reference_voltage()            
CHANNELS = ['in0/ref', 'in1/ref', 'in2/ref']
import os
type='Linux'
window = Tk()
window.title("Systems Automatic Mode Rev 1.")
window.geometry('408x340') # ('408x310')
window.resizable(True, True)# expands window both ways x and y.


def update_cpu_temperature():
    cpu = CPUTemperature()
#    cpu_temp=(cpu.temperature)
    cpu_temp=["CPU- (cpu.temperature)*C"]# this displays CPU- x.xx*C bad code?
    cpu_label.config(text = cpu_temp)

window.after(1000, update_cpu_temperature)


def update_sensor():# data pin conected to pin 3 SDA (bus).
    sensor = W1ThermSensor()
    while True:
        temperature = sensor.get_temperature()
        AirCon_sensor = ("Cabin temperature = %s celsius" % temperature)
        aircon_label = (text = AirCon_sensor)
    
window.after(1000, update_sensor)


def clock():
    date2_time = '  '
    date_time = datetime.datetime.now().strftime("%d-%m-%Y %H:%M:%S/%p")
    date,time1 = date_time.split()
    time2,time3 = time1.split('/')
    hour,minutes,seconds =  time2.split(':')
    if int(hour) > 11 and int(hour) < 24:
        time = str(int(hour) - 12) + ':' + minutes + ':' + seconds + ' ' + time3
    else:
        time = time2 + ' ' + time3
    time_label.config(text = time)
    date_label.config(text= date)
    date2_label.config(text = date2_time)
    time_label.after(1000, clock)

def alarm():
    main_time = datetime.datetime.now().strftime("%H:%M %p")
    alarm_time = get_alarm_time_entry.get()
    alarm_time1,alarm_time2 = alarm_time.split(' ')
    alarm_hour, alarm_minutes = alarm_time1.split(':')
    main_time1,main_time2 = main_time.split(' ')
    main_hour1, main_minutes = main_time1.split(':')
    if main_time2 == 'PM':
        main_hour = str(int(main_hour1) - 12)
    else:
        main_hour = main_hour1
    if int(alarm_hour) == int(main_hour) and int(alarm_minutes) == int(main_minutes) and main_time2 == alarm_time2:

        os.system('beep -f 5000')# beep through Linux sys.

        alarm_status_label.config(text='Time Is Up')

        get_alarm_time_entry.config(state='enabled')
        set_alarm_button.config(state='enabled')
        get_alarm_time_entry.delete(0,END)# END is not defined  ########################
        alarm_status_label.config(text = '')
    else:
        alarm_status_label.config(text='Alarm Has Started')
        get_alarm_time_entry.config(state='disabled')
        set_alarm_button.config(state='disabled')
    alarm_status_label.after(1000, alarm)

def updateVolts():#Iterate over the channels and labels to update them in turn.
    for channel, label in zip(CHANNELS,labels):
        value = ads1015.get_compensated_voltage(channel=channel, reference_voltage=reference)
        current_volts = ('   {}  ---  {:6.3f} volts   '.format(channel, value))
        label.config(text = current_volts)
    window.after(1000,updateVolts)#Wait 1 second before updating again
 
def updateSolar():# in0 used to monitor solar volts of hotwater system.
    for channel in CHANNELS:
        value = ads1015.get_compensated_voltage(channel=channel, reference_voltage=reference)
        if channel == 'in0/ref':
#            current0_channel = ''
            current1_channel = 'Hotwater'
            if True:#using a conditional statement with a constant value ################################
                if value >= 2.000 and value <= 19.000:# voltage range of print solar voltage.
                    current_value = 'HW SOLAR'
                elif value <= 1.999:# voltage range of print no solar input.
                    current_value = 'HW NO SOLAR'
                elif value >= 19.001 and  22.500:# voltage range of print no solar input.
                    current_value = 'HW SOLAR'                   
                else:
                    current_value = 'WARNING: SOLAR SYSTEM OVERVOLTAGE'# print warning
                solar_label.config(text = current_value)
#                solar2_label.config(text = current0_value)
                power1_label.config(text = current1_channel)
                
            window.after(1000, updateSolar)


def updateMain():
    for channel in CHANNELS:# in1 used to monitor main solar bank. 
        value = ads1015.get_compensated_voltage(channel=channel, reference_voltage=reference)
        if channel == 'in1/ref':
            current2_channel = 'Solar'
            if True:# using a conditional statement with a constant value ##################################
                if value >= 2.000 and value <= 17.500:# voltage range of print solar voltage.
                    main_value = 'MAINS:SOLAR'
                elif value <= 1.999:# voltage range of print no solar input.
                    main_value = 'MAINS:NO SOLAR'
                elif value >= 17.501 and 22.500:# voltage range of print no solar input.
                    main_value = 'MAINS SOLAR'    
                else:
                    main_value = 'WARNING: MAINS SOLAR OVERVOLTAGE'    
                main_label.config(text = main_value)
                power2_label.config(text = current2_channel)
            window.after(1000, updateSolar)

def updateBattery():# in2 displays battery status.
    for channel in CHANNELS:
        value = ads1015.get_compensated_voltage(channel=channel, reference_voltage=reference)
        if channel == 'in2/ref':
            current3_channel = 'Battery'
            if True:# using a conditional statement with a constant value  #############################
                if value <= 11.000:# range in battery capacity.
                    battery_value = 'SYSTEM DEAD RECHARGE OR BURY NOW'# code stuck here instead of line 169 elif value >= 13.501 and value <= 13.800: 
                    data_value = 'HOTWATER SYSTEM off'
#                    bus.write_byte_data(DEVICE_ADDR, 2, 0x00)# ensures hotwater system is off and hasnt latched on by other means.
#                    bus.write_byte_data(DEVICE_ADDR, 3, 0x00)# turns off relay 3 audio alarm.
#                    bus.write_byte_data(DEVICE_ADDR, 4, 0xFF)# turns on relay 4 and 300A slave relay (using NC/COM contacts) ON DISCONNECTING BATTERY FROM CIRCUIT.
#                    300A relay not installed (yet to be delivered).
             
                elif value >= 11.001 and value <= 11.999:# range in battery capacity
                    battery_value = 'SYSTEM DYING RECHARGE NOW'
                    data_value = 'HOTWATERR SYSTEM off'
#                    bus.write_byte_data(DEVICE_ADDR, 3, 0x00)# turns off relay audio warning
#                    bus.write_byte_data(DEVICE_ADDR, 2, 0x00)# turn off relay 2 hotwater.
                   
                elif value >= 12.000 and value <= 12.200:# range in battery capacity.
                    battery_value = 'SYSTEM LOW RECHARGE NOW'
                    data_value = 'HOTWATER SYSTEM  off'
#                    bus.write_byte_data(DEVICE_ADDR, 2, 0x00)# turn off relay 2 hotwater.
                    
                elif value >= 12.201 and value <= 13.000:# range in battery capacity.
                    battery_value =  'SYSTEM ON BATTERY'
                    data_value = 'HOTWATER SYSTEM  off'
#                    bus.write_byte_data(DEVICE_ADDR, 2, 0x00)# turn off relay 2 hotwater.
                    
                elif value >= 13.001 and value <= 13.250:# range for bulk mode charging
                    battery_value =  'SYSTEM BULK'
                    data_value = 'HOTWATER SYSTEM  off'
                    
                elif value >= 13.251 and value <= 13.500:# range for bulk mode charging
                    battery_value =  'CHARGING SYSTEM BULK'
                    data_value = 'HOTWATER SYSTEM  on'
#                    bus.write_byte_data(DEVICE_ADDR, 2, 0xFF)# turn on relay 2 hotwater.

                elif value >= 13.501 and value <= 13.800:# range of float mode
                    battery_value = 'CHARGING SYSTEM FLOAT'
                    data_value = 'HOTWATER SYSTEM  on'
#                    bus.write_byte_data(DEVICE_ADDR, 2, 0xFF)# turn on relay 2 hotwater.
  
                elif value >= 13.801 and value <= 14.500:# range of absorbsion mode
                    battery_value = 'CHARGING SYSTEM ABSORBSION'
                    data_value = 'HOTWATER SYSTEM  on'
#                    bus.write_byte_data(DEVICE_ADDR, 2, 0xFF)# turn on relay 2 hotwater.
  
                elif value >= 14.501 and value <= 15.500:# calcium mode thresholds 15.500v restores full battery capacity in heavily discharged batteries
#                   (not calcified or sulphated sla's which require aditional venting and full 16v charge)
                    battery_value = 'CHARGING SYSTEM CALCIUM MODE'
                    data_value = 'HOTWATER SYSTEM  off'
#                    bus.write_byte_data(DEVICE_ADDR, 2, 0x00)# switches off relay 2 hotwater (system may be in fault or calcium mode).

                elif value >= 15.501 and value <= 16.000:# voltage range to trip following code.
                    battery_value = 'SYSTEMS WARNING: CALCIIUM MODE'
                    data_value = 'TRIP SYSTEM NOW'
#                    bus.write_byte_data(DEVICE_ADDR, 4, 0xFF) # relay 4 option to isolate batteries above 15.501v.
#                    bus.write_byte_data(DEVICE_ADDR, 2, 0x00)# switches off relay 2 hotwater (system may be in fault or calcium mode).
                 
                else: #value >= 16.001v trips following code.
                    battery_value = 'SYSTEMS WARNING:'
                    data_value = 'OVERVOLTAGE FAULT <16v'
#                    bus.write_byte_data(DEVICE_ADDR, 4, 0xFF) # turns on relay 4 and isolates batteries from overvoltage faults <+16v, 
#                    bus.write_byte_data(DEVICE_ADDR, 2, 0x00)# switches off relay 2 hotwater (system may be in fault or calcium mode).
#                    bus.write_byte_data(DEVICE_ADDR, 3, 0xFF)# audio warning of fault or calcium mode
#                    bus.write_byte_data(DEVICE_ADDR, 3, 0x00)# turns off relay 3 audio alarm.
                    
                battery_label.config(text = battery_value)
                data_label.config(text = data_value)
                power3_label.config(text = current3_channel)
            window.after(1000, updateBattery)

tabs_control = Notebook(window)

clock_tab = Frame(tabs_control)
alarm_tab = Frame(tabs_control)
systems_tab = Frame(tabs_control)
temp_tab = Frame(tabs_control)
emergency_tab = Frame(tabs_control)

tabs_control.add(clock_tab, text='Voltages.')
tabs_control.add(alarm_tab, text='Alarms.')
tabs_control.add(systems_tab, text='Systems.')
tabs_control.add(temp_tab, text='Security.')
tabs_control.add(emergency_tab, text ='Emergency Mode.')

tabs_control.pack(expand = 1, fill ="both")

date2_label = Label(clock_tab, font = 'calibri 5 bold', foreground = 'black')
date2_label.pack(anchor='n') #position (top)
date_label = Label(clock_tab, font = 'calibri 15 bold', foreground = 'black')
date_label.pack(anchor='n') #position (top)
time_label = Label(clock_tab, font = 'calibri 27 bold', foreground = 'black') # added module here
time_label.pack(anchor='center')

power1_label = Label(clock_tab, font = 'Times 13 bold', foreground='black')
power1_label.pack(anchor='s')
volts_label1 = Label(clock_tab, font = 'Times 22 bold', foreground='black')
volts_label1.pack(anchor='s')
power2_label = Label(clock_tab, font = 'Times 13 bold', foreground='black')
power2_label.pack(anchor='s')
volts_label2 = Label(clock_tab, font = 'Times 22 bold', foreground='black')
volts_label2.pack(anchor='s')
power3_label = Label(clock_tab, font = 'Times 13 bold', foreground='black')
power3_label.pack(anchor='s')
volts_label3 = Label(clock_tab, font = 'Times 22 bold', foreground='black')
volts_label3.pack(anchor='s')
labels = [volts_label1, volts_label2, volts_label3]

get_alarm_time_entry = Entry(alarm_tab, font = 'calibri 15 bold')
get_alarm_time_entry.pack(anchor='center')
alarm_instructions_label = Label(alarm_tab, font = 'calibri 12 bold', text = "Enter Alarm Time. Eg -> 01:30 PM, 01 -> Hour, 30 -> Minutes")
alarm_instructions_label.pack(anchor='s')
set_alarm_button = Button(alarm_tab, text = "Set Alarm", command=alarm)
set_alarm_button.pack(anchor='s')
alarm_status_label = Label(alarm_tab, font = 'calibri 15 bold')
alarm_status_label.pack(anchor='s')


cpu_label = Label(systems_tab, font = 'calibri 15 bold', foreground = 'black')
cpu_label.pack(anchor='n') #position

aircon_label = Label(systems_tab, font = 'calibri 15 bold', foreground = 'black')
aircon_label.pack(anchor='n')

#solar2_label = Label(systems_tab, font = 'calibri 15 bold', foreground = 'black')
#solar2_label.pack(anchor='n') #position
solar_label = Label(systems_tab, font = 'calibri 15 bold', foreground = 'black')
solar_label.pack(anchor='n') #position
main_label = Label(systems_tab, font = 'calibri 15 bold', foreground = 'black')
main_label.pack(anchor='center') #position
battery_label = Label(systems_tab, font = 'calibri 15 bold', foreground = 'black')
battery_label.pack(anchor='n') #position
data_label = Label(systems_tab, font = 'calibri 15 bold', foreground = 'black')
data_label.pack(anchor='s') #position

##################  still to do  #######################
#temp_label = Label(battery_tab, font = 'calibri 31 bold', foreground = 'black') # added module here
#temp_label.pack(anchor='center')
#emergency_label = Label(emergency_tab, font = 'calibri 31 bold', foreground = 'black') # added module here
#emergency_label.pack(anchor='center')
#emergency_shut_down = Button(emergency_tab, text='Emergency Shut Down', state='disabled',command=lambda:emergency('stop'))
#emergency_shut_down.pack(anchor='center')
#emergency_reset = Button(emergency_tab, text='Reset', state='enabled',command=lambda:emergency('reset'))
#emergency_reset.pack(anchor='center')
#emergency_over_ride = Button(emergency_tab, text='Emergency mode', state='disabled', command=lambda:stopwatch('reset'))
#emergency_over_ride_reset.pack(anchor='center')
##########################################################

window.after_idle(update_sensor)

window.after_idle(updateBattery)
window.after_idle(updateVolts) #Call the updateVolts function after the gui has loaded
window.after_idle(updateSolar)
window.after_idle(updateMain)

clock()
window.mainloop()
i used the following temperature sensor code in the above

Code: Select all

from gpiozero import CPUTemperature

from w1thermsensor import W1ThermSensor# temp one wire pi config enabled.
#temperature sensor data to pi pin 3, Vin 3.3v pin 1, ground to pin 9.
def update_sensor():# data pin conected to pin 3 SDA (bus).
    sensor = W1ThermSensor()
    while True:
        temperature = sensor.get_temperature()
        AirCon_sensor = ("Cabin temperature = %s celsius" % temperature)
        aircon_label = (text = AirCon_sensor)
    
window.after(1000, update_sensor)
because when i ran the following solo it crashed my computer turning it off

Code: Select all

# -*- coding: utf-8 -*-
import glob
import time
import os
import sys

#  An Example Reading from /sys/bus/w1/devices/<ds18b20-id>/w1_slave
#  a6 01 4b 46 7f ff 0c 10 5c : crc=5c YES
#  a6 01 4b 46 7f ff 0c 10 5c t=26375

import RPi.GPIO as GPIO

#  Set Pullup mode on GPIO14 first.
GPIO_PIN_NUMBER=3
GPIO.setmode(GPIO.BCM)
GPIO.setup(GPIO_PIN_NUMBER, GPIO.IN, pull_up_down=GPIO.PUD_UP)

def ds18b20_read_sensors():
  rtn = {}
  w1_devices = []
  w1_devices = os.listdir("/sys/bus/w1/devices/")
  for deviceid in w1_devices:
    rtn[deviceid] = {}
    rtn[deviceid]['temp_c'] = None
    device_data_file = "/sys/bus/w1/devices/" + deviceid + "/w1_slave"
    if os.path.isfile(device_data_file):
      try:
         f = open(device_data_file, "r")
         data = f.read()
         f.close()
         if "YES" in data:
           (discard, sep, reading) = data.partition(' t=')
           rtn[deviceid]['temp_c'] = float(reading) / float(1000.0)
         else:
           rtn[deviceid]['error'] = 'No YES flag: bad data.'
      except Exception as e:
         rtn[deviceid]['error'] = 'Exception during file parsing: ' + str(e)
    else:
      rtn[deviceid]['error'] = 'w1_slave file not found.'
  return rtn;

while True:
  temp_readings = ds18b20_read_sensors()
  for t in temp_readings:
    if not 'error' in temp_readings[t]:
      value = (u"Device id '%s' reads %.3f +/- 0.5 °C" % (t, temp_readings[t]['temp_c']))
      temp_label.config(text = value)
    window.after(1000, ds18b20_read_sensors)
i dont know why it crashed my computer, so i changed it to the new sensor code and i had to paste a new elf in the boot directory to get computer working again.
can someone that a look at the new code as i dont want to crash it again...
is using pin 3 for sensor data input even though it has relay module, power board and ADS hooked to it ( ds20b18 should have a bus function).
the sensor has a built in 4.7k resistor and capacitor so i didnt add another.
Thankyou.

User avatar
Paeryn
Posts: 3347
Joined: Wed Nov 23, 2011 1:10 am
Location: Sheffield, England

Re: combining a .py script into a Tk gui

Sun Aug 08, 2021 2:44 am

If_i_only_knew101 wrote:
Sun Aug 08, 2021 1:51 am
hi im not sure about the cpu temperature print function i cant seem to get
cpu xx.xx *C to print and the new part temperature sensor i just dont know...

Code: Select all

def update_sensor():# data pin conected to pin 3 SDA (bus).
    sensor = W1ThermSensor()
    while True:
        temperature = sensor.get_temperature()
        AirCon_sensor = ("Cabin temperature = %s celsius" % temperature)
        aircon_label = (text = AirCon_sensor)
    
window.after(1000, update_sensor)
You can't have an endless while loop here. You've told the GUI to call this function after a second has passed, when the GUI gets around to doing so it will get stuck as the function never returns control back to the GUI so nothing will update and no more events will be processed.
If_i_only_knew101 wrote:
Sun Aug 08, 2021 1:51 am
because when i ran the following solo it crashed my computer turning it off

Code: Select all

# -*- coding: utf-8 -*-
import glob
import time
import os
import sys

#  An Example Reading from /sys/bus/w1/devices/<ds18b20-id>/w1_slave
#  a6 01 4b 46 7f ff 0c 10 5c : crc=5c YES
#  a6 01 4b 46 7f ff 0c 10 5c t=26375

import RPi.GPIO as GPIO

#  Set Pullup mode on GPIO14 first.
GPIO_PIN_NUMBER=3
GPIO.setmode(GPIO.BCM)
GPIO.setup(GPIO_PIN_NUMBER, GPIO.IN, pull_up_down=GPIO.PUD_UP)

def ds18b20_read_sensors():
  rtn = {}
  w1_devices = []
  w1_devices = os.listdir("/sys/bus/w1/devices/")
  for deviceid in w1_devices:
    rtn[deviceid] = {}
    rtn[deviceid]['temp_c'] = None
    device_data_file = "/sys/bus/w1/devices/" + deviceid + "/w1_slave"
    if os.path.isfile(device_data_file):
      try:
         f = open(device_data_file, "r")
         data = f.read()
         f.close()
         if "YES" in data:
           (discard, sep, reading) = data.partition(' t=')
           rtn[deviceid]['temp_c'] = float(reading) / float(1000.0)
         else:
           rtn[deviceid]['error'] = 'No YES flag: bad data.'
      except Exception as e:
         rtn[deviceid]['error'] = 'Exception during file parsing: ' + str(e)
    else:
      rtn[deviceid]['error'] = 'w1_slave file not found.'
  return rtn;

while True:
  temp_readings = ds18b20_read_sensors()
  for t in temp_readings:
    if not 'error' in temp_readings[t]:
      value = (u"Device id '%s' reads %.3f +/- 0.5 °C" % (t, temp_readings[t]['temp_c']))
      temp_label.config(text = value)
    window.after(1000, ds18b20_read_sensors)
You've got an endless while loop that is constantly calling ds18b20_read_sensors() and adding a callback for the GUI to also call ds18b20_read_sensors() in a second's time, and the code looks like it will execute each pass of the loop fairly quickly (like, thousands of times a second). The GUI's mainloop (which you've not supplied in this, I'll assume this code was part of the bigger program) will never get to do anything once this loop starts so eventually it'll run out memory if nothing else.

I don't see anything that would cause the filesystem to become corrupt, I'd expect the kernel to kill your program if Tk doesn't cause it to terminate itself first.
She who travels light — forgot something.
Please note that my name doesn't start with the @ character so can people please stop writing it as if it does!

scotty101
Posts: 4282
Joined: Fri Jun 08, 2012 6:03 pm

Re: combining a .py script into a Tk gui

Mon Aug 09, 2021 7:52 am

Paeryn wrote:
Sun Aug 08, 2021 2:44 am
If_i_only_knew101 wrote:
Sun Aug 08, 2021 1:51 am
hi im not sure about the cpu temperature print function i cant seem to get
cpu xx.xx *C to print and the new part temperature sensor i just dont know...

Code: Select all

def update_sensor():# data pin conected to pin 3 SDA (bus).
    sensor = W1ThermSensor()
    while True:
        temperature = sensor.get_temperature()
        AirCon_sensor = ("Cabin temperature = %s celsius" % temperature)
        aircon_label = (text = AirCon_sensor)
    
window.after(1000, update_sensor)
You can't have an endless while loop here. You've told the GUI to call this function after a second has passed, when the GUI gets around to doing so it will get stuck as the function never returns control back to the GUI so nothing will update and no more events will be processed.
Yep. You've made the same mistake that I helped you resolve at the very start of this topic. NEVER use an infinite while loop with Tkinter.

And this line

Code: Select all

aircon_label = (text = AirCon_sensor)
Should probably be

Code: Select all

aircon_label.config(text = AirCon_sensor)
Electronic and Computer Engineer
Pi Interests: Home Automation, IOT, Python and Tkinter

If_i_only_knew101
Posts: 37
Joined: Mon Jul 19, 2021 12:54 am

Re: combining a .py script into a Tk gui

Mon Aug 09, 2021 9:55 am

scotty101 wrote:
Mon Aug 09, 2021 7:52 am
Paeryn wrote:
Sun Aug 08, 2021 2:44 am
If_i_only_knew101 wrote:
Sun Aug 08, 2021 1:51 am
hi im not sure about the cpu temperature print function i cant seem to get
cpu xx.xx *C to print and the new part temperature sensor i just dont know...

Code: Select all

def update_sensor():# data pin conected to pin 3 SDA (bus).
    sensor = W1ThermSensor()
    while True:
        temperature = sensor.get_temperature()
        AirCon_sensor = ("Cabin temperature = %s celsius" % temperature)
        aircon_label = (text = AirCon_sensor)
    
window.after(1000, update_sensor)
You can't have an endless while loop here. You've told the GUI to call this function after a second has passed, when the GUI gets around to doing so it will get stuck as the function never returns control back to the GUI so nothing will update and no more events will be processed.
Yep. You've made the same mistake that I helped you resolve at the very start of this topic. NEVER use an infinite while loop with Tkinter.

And this line

Code: Select all

aircon_label = (text = AirCon_sensor)
Should probably be

Code: Select all

aircon_label.config(text = AirCon_sensor)
yeah sorry i see the aircon label mistake now my bad.
as for the endless loop i remember you shouldnt use time sleep function but use instead-

Code: Select all

window.after(1000, update_sensor)
this waits a second and updates the def every second (cutting the loop from nano second update to call every second.
at the end with)

Code: Select all

window.after_idle(update_sensor)
window.after_idle(updateBattery)
window.after_idle(updateVolts) #Call the updateVolts function after the gui has loaded
window.after_idle(updateSolar)
window.after_idle(updateMain)

clock()
window.mainloop()
which calls the update function after the gui has loaded.
same as the update volts part

Code: Select all

def updateVolts():#Iterate over the channels and labels to update them in turn.
    for channel, label in zip(CHANNELS,labels):
        value = ads1015.get_compensated_voltage(channel=channel, reference_voltage=reference)
        current_volts = ('   {}  ---  {:6.3f} volts   '.format(channel, value))
        label.config(text = current_volts)

    window.after(1000,updateVolts)#Wait 1 second before updating again
window.after_idle(updateVolts) #Call the updateVolts function after the gui has loaded
clock()
window.mainloop()
i do apologise, im struggling with python code, have i got the above right?
(untill now i was electrical side only) the oldies at mens shed are destroying their battery banks by more output than in, and deep discharge. a automatic system would make my life easier and stop them running to me with this problem. trouble is the old girls want cameras to see their pets the blokes want camera security and none of them know how hard it is for me. I do thank you as id be totally stuffed without the help...
edit im just trying to get through what they need and hope to learn to do what they want...

Return to “Python”