Asymic
Posts: 29
Joined: Sun Jun 16, 2019 8:28 am

Tkinter Dash

Sun Aug 11, 2019 7:01 am

I have built a PiTablet and want a dash board to show battery level and processor temperature. I also want 3 checkbuttons for a few settings. I am struggling to both draw the rectangles for the bar gauges (on canvas) and insert check boxes in the one window. Code follows:-

Code: Select all

import tkinter as tk
from tkinter import *

class Example(Frame): 

    def __init__(self):
        super().__init__() 
        self.initUI() 

    def initUI(self): 

        self.master.title("Dash")
        self.pack(fill=BOTH, expand=1) 
        canvas = Canvas(self)
        canvas.create_rectangle(10, 10, 60, 110,
             outline="#000", fill="#fb0")
        canvas.create_rectangle(80, 10, 130, 110,
             outline="#000", fill="#f50")
        canvas.create_rectangle(150, 10, 200, 110,
             outline="#000", fill="#05f")
        canvas.create_text(18, 140, anchor="w", font="Arial",
             text="Volts      Charge      Temp ")
        Dim = tk.IntVar()
        canvas.pack(fill=BOTH, expand=1) 
        tk.Checkbutton(self.master, text="Dim OK", variable = Dim) #, tk.grid(row = 0, sticky = W)


def main(): 
    root = Tk()
    ex = Example()
    root.geometry("210x250+580+150")
    root.mainloop() 

if __name__ == '__main__':
    main() 

As I have done nothing like this with Python before I am rather lost, and have a few questions which hopefully someone can help me with.

Am I starting in the right direction?
Can I combine Bar gauges and checkbuttons in onw window? How?
Can I then paste filled rectangles of varying height from my loop of code into the existing rectangles for my bar gauge?

Thank you for any help.

User avatar
B.Goode
Posts: 8217
Joined: Mon Sep 01, 2014 4:03 pm
Location: UK

Re: Tkinter Dash

Sun Aug 11, 2019 7:13 am

Maybe the guizero library would be an easier starting point?
guizero is a Python 3 library for creating simple GUIs.

It is designed to allow new learners to quickly and easily create GUIs for their programs.

...

The aim of guizero is to make the process of creating simple GUIs quick, accessible and understandable for new learners.

Works with standard Python Tkinter GUI library (and no need to install other libraries)
Ref: https://lawsie.github.io/guizero/about/


Main guizero website: https://lawsie.github.io/guizero/

gordon77
Posts: 4107
Joined: Sun Aug 05, 2012 3:12 pm

Re: Tkinter Dash

Sun Aug 11, 2019 11:30 am

Try this...

Code: Select all

import tkinter as tk
from tkinter import *

class Example(Frame):
    
    def __init__(self):
        super().__init__() 
        self.initUI()
        

    def initUI(self): 
        global canvas
        self.master.title("Dash")
        self.pack(fill=BOTH, expand=1) 
        canvas = Canvas(self)
        canvas.create_rectangle(10, 10, 60, 110,
             outline="#000", fill="#fb0")
        canvas.create_rectangle(80, 10, 130, 110,
             outline="#000", fill="#f50")
        canvas.create_rectangle(150, 10, 200, 110,
             outline="#000", fill="#05f")
        canvas.create_text(18, 140, anchor="w", font="Arial",
             text="Volts      Charge      Temp ")
        Dim = tk.IntVar()
        Dim2 = tk.IntVar()
        Dim3 = tk.IntVar()
        button1 = tk.Checkbutton(self.master, text="Dim OK", variable = Dim, width = 5) 
        button1.place(x=20, y=160)
        button2 = tk.Checkbutton(self.master, text="No2 OK", variable = Dim2, width = 5) 
        button2.place(x=20, y=190)
        button3 = tk.Checkbutton(self.master, text="No3 OK", variable = Dim3, width = 5) 
        button3.place(x=20, y=220)
        canvas.pack(fill=BOTH, expand=1)
        self.update_temp()
        
    def update_temp(self):
        global canvas
        f = open("/sys/class/thermal/thermal_zone0/temp", "r")
        t = int(f.readline ())/1000
        canvas.create_rectangle(150, 10, 200, 110,
             outline="#000", fill="#05f")
        canvas.create_rectangle(150, 110, 200, 110-t,
             outline="#000", fill="#fb0")
        canvas.create_text(166, 90, anchor="w", font="Arial",
             text=str(int(t)))
        self.after(1000, self.update_temp)

def main(): 
    root = Tk()
    ex = Example()
    root.geometry("210x250+580+150")
    root.mainloop() 

if __name__ == '__main__':
    main() 
Attachments
dash2.jpg
dash2.jpg (12.12 KiB) Viewed 2244 times

Asymic
Posts: 29
Joined: Sun Jun 16, 2019 8:28 am

Re: Tkinter Dash

Sun Aug 11, 2019 12:24 pm

Hello Gordon,

I can only say I am somewhat dumbfounded by the speed and thoroughness of your reply. Thank you so much!

I need to have a bit of a study here, and then lever in my ADC routine and scripts for the buttons.

I take it I could call my ADC def, for battery volts in the update_temp routine?

The buttons are planned to allow dimming when idle (RPI touchscreen); Turn on my mono amp (which I do via an icon to GPIO16; and to turn on WiFi. Would I also look at my button variable and set outputs here too?

I tried to post a picture in here of my tablet, but this seems to be beyond me at the moment too!

Thank you again!

gordon77
Posts: 4107
Joined: Sun Aug 05, 2012 3:12 pm

Re: Tkinter Dash

Sun Aug 11, 2019 1:23 pm

Code: Select all

import tkinter as tk
from tkinter import *
import os
import RPi.GPIO as GPIO

GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
GPIO.setup(16,GPIO.OUT)
GPIO.output(16,GPIO.LOW)

class Example(Frame):
    
    def __init__(self):
        super().__init__() 
        self.initUI()

    def initUI(self): 
        global canvas,wifi,amp, dim
        self.master.title("Dash")
        self.pack(fill=BOTH, expand=1) 
        canvas = Canvas(self)
        canvas.create_rectangle(10, 10, 60, 110,
             outline="#000", fill="#fb0")
        canvas.create_rectangle(80, 10, 130, 110,
             outline="#000", fill="#f50")
        canvas.create_rectangle(150, 10, 200, 110,
             outline="#000", fill="#05f")
        canvas.create_text(18, 140, anchor="w", font="Arial",
             text="Volts      Charge      Temp ")
        dim = tk.IntVar()
        amp = tk.IntVar()
        wifi = tk.IntVar()
        button1 = tk.Checkbutton(self.master, text="Dim OK", variable = dim, width = 5, command=self.Dim) 
        button1.place(x=20, y=160)
        button2 = tk.Checkbutton(self.master, text="Amp ON", variable = amp, width = 6, command=self.Amp) 
        button2.place(x=18, y=190)
        button3 = tk.Checkbutton(self.master, text="Wifi ON", variable = wifi, width = 5, command=self.Wifi) 
        button3.place(x=20, y=220)
        canvas.pack(fill=BOTH, expand=1)
        self.update_temp()
        
    def update_temp(self):
        global canvas
        f = open("/sys/class/thermal/thermal_zone0/temp", "r")
        t = int(f.readline ())/1000
        canvas.create_rectangle(150, 10, 200, 110-t,
             outline="#000", fill="#888")
        if t > 80:
            canvas.create_rectangle(150, 110, 200, 110-t,
             outline="#000", fill="#f00")
        elif t > 60:
            canvas.create_rectangle(150, 110, 200, 110-t,
             outline="#000", fill="#fc0")
        else:
            canvas.create_rectangle(150, 110, 200, 110-t,
             outline="#000", fill="#0f0")
        canvas.create_text(166, 90, anchor="w", font="Arial",
             text=str(int(t)))

        # generate Volt reading here, value = v
        v = 5.12
        w = v * 10
        canvas.create_rectangle(10, 10, 60, 110-w,
             outline="#000", fill="#888")
        canvas.create_rectangle(10, 110, 60, 110-w,
             outline="#000", fill="#fc0")
        canvas.create_text(20, 90, anchor="w", font="Arial",
             text=str(v))

        # generate charge reading here, value = c
        c = 75
        canvas.create_rectangle(80, 10, 130, 110-c,
             outline="#000", fill="#888")
        canvas.create_rectangle(80, 110, 130, 110-c,
             outline="#000", fill="#a4c")
        canvas.create_text(96, 90, anchor="w", font="Arial",
             text=str(c))
        
        self.after(1000, self.update_temp)
        
    def Wifi(self):
        if wifi.get() == 0:
            path = "sudo rfkill block wifi"
        else:
            path = "sudo rfkill unblock wifi"
        os.system (path)
        
    def Amp(self):
        if amp.get() == 0:
            GPIO.output(16,GPIO.LOW)
        else:
            GPIO.output(16,GPIO.HIGH)
            
    def Dim(self):
        if dim.get() == 0:
           print ("undimming")
           # undimming code here...
        else:
           # dimming code here...
           print ("dimming")
           
             

def main(): 
    root = Tk()
    ex = Example()
    root.geometry("210x250+580+150")
    root.mainloop() 

if __name__ == '__main__':
    main() 
 
Attachments
dash2.jpg
dash2.jpg (12.63 KiB) Viewed 2205 times

Asymic
Posts: 29
Joined: Sun Jun 16, 2019 8:28 am

Re: Tkinter Dash

Mon Aug 12, 2019 6:39 am

Hi Gordon,

Once again I can not thank you enough for this.

I have put my ADC code in and am getting true battery volts, and calculating charge too.

Despite the amount you have done here, I have learned a lot. I don't know how long it would have taken to have discovered these techniques!

Thank you
Grant

Asymic
Posts: 29
Joined: Sun Jun 16, 2019 8:28 am

Re: Tkinter Dash

Mon Aug 12, 2019 3:05 pm

Can anybody tell where I can read the user idle time, so that I can dim the display?

Thank you.

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

Re: Tkinter Dash

Mon Aug 12, 2019 3:16 pm

Asymic wrote:
Mon Aug 12, 2019 3:05 pm
Can anybody tell where I can read the user idle time, so that I can dim the display?
That's the job of a screen saver not something you code in to your application.
Look for xscreensaver.
Electronic and Computer Engineer
Pi Interests: Home Automation, IOT, Python and Tkinter

Asymic
Posts: 29
Joined: Sun Jun 16, 2019 8:28 am

Re: Tkinter Dash

Mon Aug 12, 2019 5:44 pm

This guy has done it:-

http://www.stefanv.com/electronics/a-co ... ablet.html

But Looking through his code I am a little lost as to how he gets the idle seconds.

gordon77
Posts: 4107
Joined: Sun Aug 05, 2012 3:12 pm

Re: Tkinter Dash

Tue Aug 13, 2019 1:51 pm

Some ideas...

He refers to https://superuser.com/questions/638357

where they suggest xprintidle , to install use sudo apt-get install xprintidle

Then try this...

Code: Select all

import tkinter as tk
from tkinter import *
import os
import RPi.GPIO as GPIO
from random import *
from subprocess import PIPE, run

GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
GPIO.setup(16,GPIO.OUT)
GPIO.output(16,GPIO.LOW)

class Example(Frame):
    
    def __init__(self):
        super().__init__() 
        self.initUI()

    def initUI(self): 
        global canvas,wifi,amp, dim, idle, dimmed
        dimmed = 0
        self.master.title("Dash")
        self.pack(fill=BOTH, expand=1) 
        canvas = Canvas(self)
        canvas.create_rectangle(10, 10, 60, 110,
             outline="#000", fill="#fb0")
        canvas.create_rectangle(80, 10, 130, 110,
             outline="#000", fill="#f50")
        canvas.create_rectangle(150, 10, 200, 110,
             outline="#000", fill="#05f")
        canvas.create_text(18, 140, anchor="w", font="Arial",
             text="Volts      Charge      Temp ")
        dim = tk.IntVar()
        amp = tk.IntVar()
        wifi = tk.IntVar()
        button1 = tk.Checkbutton(self.master, text="Dim OK", variable = dim, width = 5)  
        button1.place(x=20, y=160)
        button2 = tk.Checkbutton(self.master, text="Amp ON", variable = amp, width = 6, command=self.Amp) 
        button2.place(x=18, y=190)
        button3 = tk.Checkbutton(self.master, text="Wifi ON", variable = wifi, width = 5, command=self.Wifi) 
        button3.place(x=20, y=220)
        canvas.pack(fill=BOTH, expand=1)
        self.update_temp()
        
    def update_temp(self):
        global canvas, idle, dim, dimmed
        f = open("/sys/class/thermal/thermal_zone0/temp", "r")
        t = int(f.readline ())/1000
        canvas.create_rectangle(150, 10, 200, 110-t,
             outline="#000", fill="#888")
        if t > 80:
            canvas.create_rectangle(150, 110, 200, 110-t,
             outline="#000", fill="#f00")
        elif t > 60:
            canvas.create_rectangle(150, 110, 200, 110-t,
             outline="#000", fill="#fc0")
        else:
            canvas.create_rectangle(150, 110, 200, 110-t,
             outline="#000", fill="#0f0")
        canvas.create_text(166, 90, anchor="w", font="Arial",
             text=str(int(t)))

        # generate Volt reading here, value = v
        v = 4.75 + (randint(1, 50))/100
        w = v * 10
        canvas.create_rectangle(10, 10, 60, 110-w,
             outline="#000", fill="#888")
        canvas.create_rectangle(10, 110, 60, 110-w,
             outline="#000", fill="#fc0")
        canvas.create_text(20, 90, anchor="w", font="Arial",
             text=str(v))

        # generate charge reading here, value = c
        c = 50 + (randint(1, 300))/10
        canvas.create_rectangle(80, 10, 130, 110-c,
             outline="#000", fill="#888")
        canvas.create_rectangle(80, 110, 130, 110-c,
             outline="#000", fill="#a4c")
        canvas.create_text(92, 90, anchor="w", font="Arial",
             text=str(c))
        
        # Dim screen
        if dim.get() == 1:
            command = ['xprintidle']
            result = run(command, stdout=PIPE, stderr=PIPE, universal_newlines=True)
            idle = result.stdout

            dim_time = 60 # in seconds

            if int(idle) > (dim_time * 1000) and dimmed == 0:
                # put dimming code here...
                canvas.create_text(110, 170, anchor="w", font="Arial",text= "Dimmed!")
                dimmed = 1

            elif dimmed == 1 and int(idle) < (dim_time * 1000) :
                # put undimming code here...
                canvas.create_rectangle(105, 155, 190, 180, outline="#ddd", fill="#ddd")
                dimmed = 0
        
        self.after(1000, self.update_temp)
        
    def Wifi(self):
        if wifi.get() == 0:
            path = "sudo rfkill block wifi"
        else:
            path = "sudo rfkill unblock wifi"
        os.system (path)
        
    def Amp(self):
        if amp.get() == 0:
            GPIO.output(16,GPIO.LOW)
        else:
            GPIO.output(16,GPIO.HIGH)
            
          
             

def main():
    root = Tk()
    ex = Example()
    root.geometry("210x250+580+150")
    root.mainloop() 

if __name__ == '__main__':
    main() 

Asymic
Posts: 29
Joined: Sun Jun 16, 2019 8:28 am

Re: Tkinter Dash

Fri Aug 16, 2019 6:19 am

Thank you again!

For interest and if anyone is following this thread I have now nearly finished the Dash code. I will play with bar graph colours at some point.

I have shrunk the dash size down to make more room for any active window, and I have used a spare GPIO pin as a 'ghost pin' which I set when the 'Dim' checkbox is ticked. This then signals to my Daemon (which monitors my buttons, battery voltage and idle time) that it is ok to dim the display.

Shrinking the dash has resulted in the title disappearing. Is it possible to left justify window titles? (anchor=w)

The latest help from Gordon (idle time) is in the daemon code, which is also nearly there.

Here are the two sets of code if anybody is also building a Pi-Tablet:-

First the Dashboard:-

Code: Select all

import tkinter as tk
from tkinter import *
import spidev
import os
import RPi.GPIO as GPIO

GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
GPIO.setup(16,GPIO.OUT)
GPIO.output(16,GPIO.LOW)
GPIO.setup(23,GPIO.OUT)         # ghost pin, used to signal daemon dimming is ok
GPIO.output(23,GPIO.LOW)        # set here by dim chkbtn, read by daemon

spi = spidev.SpiDev()
spi.open(0,0)
spi.max_speed_hz = 500000
DEBUG = 0

def get_adc(channel):
        if ((channel > 1) or (channel < 0)):
                return -1

        r = spi.xfer2([1,(2+channel)<<6,0])
        ret = ((r[1]&31) << 6) + (r[2] >> 2)
        return ret

class Example(Frame):
    
    def __init__(self):
        super().__init__() 
        self.initUI()
        
    def initUI(self): 
        global canvas,wifi,amp, dim
        self.master.title("Dash")
        self.pack(fill=BOTH, expand=1) 
        canvas = Canvas(self)
        canvas.create_rectangle(5, 5, 45, 105,
             outline="#000", fill="#fb0")
        canvas.create_rectangle(50, 5, 90, 105,
             outline="#000", fill="#f50")
        canvas.create_rectangle(95, 5, 135, 105,
             outline="#000", fill="#05f")
        canvas.create_text(22, 120, anchor="w", font="Arial",
             text="V      Chg      T")
        dim = tk.IntVar()
        amp = tk.IntVar()
        wifi = tk.IntVar()
        button1 = tk.Checkbutton(self.master, text="Dim OK", variable = dim, width = 5, command=self.Dim) 
        button1.place(x=20, y=140)
        button2 = tk.Checkbutton(self.master, text="Amp ON", variable = amp, width = 6, command=self.Amp) 
        button2.place(x=18, y=170)
        button3 = tk.Checkbutton(self.master, text="Wifi ON", variable = wifi, width = 5, command=self.Wifi) 
        button3.place(x=20, y=200)
        canvas.pack(fill=BOTH, expand=1)
        self.update_temp()
        
    def update_temp(self):
        global canvas
        A = get_adc(0)
        V = A * 0.00484                  # scale ADC to volts
        canvas.create_rectangle(5, 5, 45, 105,
             outline="#000", fill="#fff")
        canvas.create_rectangle(5, 105, 45, 105-((V-2.8)*78),  # was 110
             outline="#000", fill="#0f0")
        canvas.create_text(8, 90, anchor="w", font="Arial",
             text=(" %1.2f" %V))

        if V > 4.1:
                C = 100
        elif V > 4.0:
                C = V * 100.0 - 310.0
        elif V > 3.65:
                C = V * 228.6 - 824.0
        elif V > 3.0:
                C = V * 15.0 - 44.75
        else:
                C = 0
        canvas.create_rectangle(50, 5, 90, 105,
             outline="#000", fill="#fff")
        canvas.create_rectangle(50, 105, 90, 105-C,
             outline="#000", fill="#f50")
        canvas.create_text(60, 90, anchor="w", font="Arial",
             text=str(int(C)))
        
        f = open("/sys/class/thermal/thermal_zone0/temp", "r")
        t = int(f.readline ())/1000
        canvas.create_rectangle(95, 5, 135, 105,
             outline="#000", fill="#fff")
        canvas.create_rectangle(95, 105, 135, 105-t,
             outline="#000", fill="#fb0")
        canvas.create_text(106, 90, anchor="w", font="Arial",
             text=str(int(t)))
        self.after(1000, self.update_temp)
  
    def Wifi(self):
        if wifi.get() == 0:
            path = "sudo rfkill block wifi"
        else:
            path = "sudo rfkill unblock wifi"
        os.system (path)
        
    def Amp(self):
        if amp.get() == 0:
            GPIO.output(16,GPIO.LOW)
        else:
            GPIO.output(16,GPIO.HIGH)
            
    def Dim(self):
        if dim.get() == 0:
            GPIO.output(23,GPIO.LOW)
        else:
            GPIO.output(23,GPIO.HIGH)
    


def main(): 
    root = Tk()
    ex = Example()
    root.geometry("140x230+650+150")
    root.mainloop() 

if __name__ == '__main__':
    main() 


and now the Daemon:-

Code: Select all

import RPi.GPIO as GPIO
from time import sleep
import subprocess
import rpi_backlight as bl
import spidev
import os, sys
from random import *
from subprocess import PIPE, run


GPIO.setmode(GPIO.BCM)
GPIO.setup(6, GPIO.IN,pull_up_down=GPIO.PUD_UP)    # button 1
GPIO.setup(13, GPIO.IN,pull_up_down=GPIO.PUD_UP)   # button 2
GPIO.setup(19, GPIO.IN,pull_up_down=GPIO.PUD_UP)   # button 3
GPIO.setup(17, GPIO.IN,pull_up_down=GPIO.PUD_UP)   # PowerBoost LBO, low when <3.2V
GPIO.setup(23, GPIO.OUT)                           # used as dimming ok flag in Dash

Beeped = 0

spi = spidev.SpiDev()
spi.open(0,0)
spi.max_speed_hz = 500000
DEBUG = 0

def get_adc(channel):                              # MCP3002
        if ((channel > 1) or (channel < 0)):
                return -1

        r = spi.xfer2([1,(2+channel)<<6,0])
        ret = ((r[1]&31) << 6) + (r[2] >> 2)
        return ret


while True:
    if GPIO.input(17) == 0:                        # PBoost LBO, battery crit low
            print("lbo is low")
            subprocess.Popen(["shutdown", "now"])
        
    if GPIO.input(6) == 0:                         # button 1 pressed
        sleep(0.5)
        if GPIO.input(6) == 0:
            print("1                       long Press")
            subprocess.Popen(["/usr/bin/amixer", "set", "PCM", "55%"])
        else:
            print("1 short press")
            temp = bl.get_actual_brightness()
            temp -=10
            bl.set_brightness(temp)
    else:
        print("1 Released")
        
    if GPIO.input(13) ==0:                         # button 2
        sleep(0.5)
        if GPIO.input(13) ==0:
            print("2                       long Press")
            subprocess.Popen(['amixer', 'set', 'Speaker', '10'])
        else:
            print("2 short press")
            temp = bl.get_actual_brightness()
            temp +=10
            bl.set_brightness(temp)
    else:
        print("2 Released")
        
    if GPIO.input(19) ==0:                         # button 3
        sleep(0.5)
        if GPIO.input(19) ==0:
            print("3                       long Press")
            subprocess.Popen(['TabDash'])
        else:
            print("3 short press")
            subprocess.Popen(['matchbox-keyboard'])
    else:
        print("3 Released")
    print(" ")
    sleep(0.1)

    # if idle>setTime & DimOk then dim scn, else bright:-

    DimOk = GPIO.input(23)  # check tick box in Dash
    if DimOk:
        print("Dim OK!")

        command = ['xprintidle']
        result = run(command, stdout=PIPE, stderr=PIPE, universal_newlines=True)
        idle = result.stdout

        dim_time = 60 # in seconds

        if int(idle) > (dim_time * 1000) and dimmed == 0:
            oBrite = bl.get_actual_brightness()      # save orig brightness
            bl.set_brightness(30)
#            canvas.create_text(110, 170, anchor="w", font="Arial",text= "Dimmed!")
            dimmed = 1

        elif dimmed == 1 and int(idle) < (dim_time * 1000) :
            bl.set_brightness(oBrite)
#            canvas.create_rectangle(105, 155, 190, 180, outline="#ddd", fill="#ddd")
            dimmed = 0


    # measure batt volts and beep if low:-

    A = get_adc(0)
    V = A * 0.00484                  # scale ADC to volts
    if V < 3.4 and not Beeped:
        Beeped = 1
        os.system('omxplayer /home/pi/Downloads/beep-01a.mp3')
     #  sys.exit()
    #break


Thanks again for the help!

Asymic
Posts: 29
Joined: Sun Jun 16, 2019 8:28 am

Re: Tkinter Dash

Fri Aug 16, 2019 6:14 pm

Regarding the Daemon code in the last post, it runs fine in the python IDLE, however when I try and run it as a service (Daemon) then I get an error that the rpi_backlight module can not be found.

Any ideas? Do I need to add a path to the "import rpi_backlight" line?

Thank you for any help!

gordon77
Posts: 4107
Joined: Sun Aug 05, 2012 3:12 pm

Re: Tkinter Dash

Sun Aug 18, 2019 2:20 pm

Use python3 to run it,

sudo pip3 install rpi-backlight if you haven't already.

Asymic
Posts: 29
Joined: Sun Jun 16, 2019 8:28 am

Re: Tkinter Dash

Tue Aug 20, 2019 5:11 am

Thank you, it needs python3.

I am now trying to run my dash code at boot, by entering the last line but one in /etc/rc.local:-

Code: Select all

#!/bin/sh -e
#
# rc.local
#
# This script is executed at the end of each multiuser runlevel.
# Make sure that the script will "exit 0" on success or any other
# value on error.
#
# In order to enable or disable this script just change the execution
# bits.
#
# By default this script does nothing.

# Print the IP address
_IP=$(hostname -I) || true
if [ "$_IP" ]; then
  printf "My IP address is %s\n" "$_IP"
fi
echo ds3231 0x68 sys/class/i2c-adapter/i2c-1/new_device
sleep 1
if [ -e /dev/rtc0 ]
then
  /sbin/hwclock -s
fi
sudo /usr/bin/python3 /home/pi/TabDash.py & > /home/pi/TabLog.txt 2>&1
exit 0

But it does not run at boot.

Originally I just tried:- sudo /usr/bin/python3 /home/pi/TabDash.py

Then I added the ampersand as I had read that if the program runs continuously this would be needed. Then I added the logging to this line, and although the log file is generated, it has zero bytes.

I also changed the permissions of TabDash.py to "anyone can execute in file manager, but this has changed nothing.

Suggestions greatly received!
Grant

User avatar
B.Goode
Posts: 8217
Joined: Mon Sep 01, 2014 4:03 pm
Location: UK

Re: Tkinter Dash

Tue Aug 20, 2019 7:06 am

The program you are trying to run is an X-windows graphical client. It can't run until an X-windows server is running.

One option is that the appropriate place to initiate your program is the configuration file /etc/xdg/lxsession/LXDE-pi/autostart

Another option is to use a systemd service.

Asymic
Posts: 29
Joined: Sun Jun 16, 2019 8:28 am

Re: Tkinter Dash

Wed Aug 21, 2019 6:26 am

Thank you, starting it in the autostart file, located in /etc/xdg/lxsession/LXDE-pi has worked.

I now have a full functioning Dash on my Tablet, and as a result I may not be adding to this thread.

Thank you all for helping. I have learnt so much.

Asymic
Posts: 29
Joined: Sun Jun 16, 2019 8:28 am

Re: Tkinter Dash

Sun Aug 25, 2019 2:18 pm

Hi Gordon,

I have glued the code from my daemon and dash together, and am a little out of depth with the way python runs main especially with the __name__ and parts like this. I am only really a simple Arduino programmer - any good articles about structuring would be good.

I am attempting to run 2 loops, one every 0.1 seconds to read buttons, and one every second to update slower things (using a loop counter in the faster loop, to call the slower loop). The trouble is I seem to have messed up the execution, and although I get an initial gui, I don't think the code is looping and none of the buttons are working.

Also when I click on "Dim Ok" button, it would appear I am not initializing the variable in the right place.

Here is my stagnant code!:-

Code: Select all

import tkinter as tk
from tkinter import *
import spidev
import os, sys
import RPi.GPIO as GPIO
from time import sleep
import subprocess
import rpi_backlight as bl
from subprocess import PIPE, run


GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
GPIO.setup(6, GPIO.IN,pull_up_down=GPIO.PUD_UP)    # button 1
GPIO.setup(13, GPIO.IN,pull_up_down=GPIO.PUD_UP)   # button 2
GPIO.setup(19, GPIO.IN,pull_up_down=GPIO.PUD_UP)   # button 3
GPIO.setup(17, GPIO.IN,pull_up_down=GPIO.PUD_UP)   # PowerBoost LBO, low when <3.2V
GPIO.setup(16,GPIO.OUT)                            # amp en
GPIO.output(16,GPIO.LOW)

spi = spidev.SpiDev()
spi.open(0,0)
spi.max_speed_hz = 500000
DEBUG = 0

dimmed = 0

def get_adc(channel):
        if ((channel > 1) or (channel < 0)):
                return -1

        r = spi.xfer2([1,(2+channel)<<6,0])
        ret = ((r[1]&31) << 6) + (r[2] >> 2)
        return ret


class Example(Frame):
    
    def __init__(self):
        super().__init__() 
        self.initUI()
        
    def initUI(self): 
        global canvas,wifi,amp, dim
        self.master.title("Dash")
        self.pack(fill=BOTH, expand=1) 
        canvas = Canvas(self)
        canvas.create_rectangle(5, 5, 45, 105,
             outline="#000", fill="#fb0")
        canvas.create_rectangle(50, 5, 90, 105,
             outline="#000", fill="#f50")
        canvas.create_rectangle(95, 5, 135, 105,
             outline="#000", fill="#05f")
        canvas.create_text(22, 120, anchor="w", font="Arial",
             text="V      Chg      T")
        dim = tk.IntVar()
        amp = tk.IntVar()
        wifi = tk.IntVar()
        button1 = tk.Checkbutton(self.master, text="Dim OK", variable = dim, width = 5, command=self.Dim) 
        button1.place(x=20, y=140)
        button2 = tk.Checkbutton(self.master, text="Amp ON", variable = amp, width = 6, command=self.Amp) 
        button2.place(x=18, y=170)
        button3 = tk.Checkbutton(self.master, text="Wifi ON", variable = wifi, width = 5, command=self.Wifi) 
        button3.place(x=20, y=200)
        canvas.pack(fill=BOTH, expand=1)
        self.Update_Slow()

    
    def Update_Slow(self):
        global canvas

        A = get_adc(0)                                          # Volts bar
        V = A * 0.00484                  # scale ADC to volts
        canvas.create_rectangle(5, 5, 45, 105,
             outline="#000", fill="#fff")
        if V > 4:
                canvas.create_rectangle(5, 105, 45, 105-((V-2.8)*78),  # was 110
             outline="#000", fill="blue")
        elif V > 3.9:
                canvas.create_rectangle(5, 105, 45, 105-((V-2.8)*78),  # was 110
             outline="#000", fill="green")
        elif V > 3.8:
                canvas.create_rectangle(5, 105, 45, 105-((V-2.8)*78),  # was 110
             outline="#000", fill="yellow")
        elif V > 3.7:
                canvas.create_rectangle(5, 105, 45, 105-((V-2.8)*78),  # was 110
             outline="#000", fill="orange")
        else:
                canvas.create_rectangle(5, 105, 45, 105-((V-2.8)*78),  # was 110
             outline="#000", fill="red")
        canvas.create_text(8, 90, anchor="w", font="Arial",
             text=(" %1.2f" %V))

                                                          # beep if batt Volts low:-
        if V < 3.4 and not Beeped:
            Beeped = 1
            os.system('omxplayer /home/pi/Downloads/beep-01a.mp3')


        if V > 4.1:                                             # Charge bar
                C = 100
        elif V > 4.0:
                C = V * 100.0 - 310.0
        elif V > 3.65:
                C = V * 228.6 - 824.0
        elif V > 3.0:
                C = V * 15.0 - 44.75
        else:
                C = 0
        canvas.create_rectangle(50, 5, 90, 105,
             outline="#000", fill="#fff")
        if C > 80:
                canvas.create_rectangle(50, 105, 90, 105-C,
             outline="#000", fill="blue")
        elif C > 40:
                canvas.create_rectangle(50, 105, 90, 105-C,
             outline="#000", fill="green")
        elif C > 30:
                canvas.create_rectangle(50, 105, 90, 105-C,
             outline="#000", fill="yellow")
        elif C > 20:
                canvas.create_rectangle(50, 105, 90, 105-C,
             outline="#000", fill="orange")
        else:
                canvas.create_rectangle(50, 105, 90, 105-C,
             outline="#000", fill="red")
        canvas.create_text(60, 90, anchor="w", font="Arial",
             text=str(int(C)))
        
        f = open("/sys/class/thermal/thermal_zone0/temp", "r")      # Temperature bar
        t = int(f.readline ())/1000
        canvas.create_rectangle(95, 5, 135, 105,
             outline="#000", fill="#fff")
        if t < 35:
                canvas.create_rectangle(95, 105, 135, 105-t,
             outline="#000", fill="blue")
        elif t < 50:
                canvas.create_rectangle(95, 105, 135, 105-t,
             outline="#000", fill="green")
        elif t < 65:
                canvas.create_rectangle(95, 105, 135, 105-t,
             outline="#000", fill="yellow")
        elif t < 80:
                canvas.create_rectangle(95, 105, 135, 105-t,
             outline="#000", fill="orange")
        else:
                canvas.create_rectangle(95, 105, 135, 105-t,
             outline="#000", fill="red")
        canvas.create_text(106, 90, anchor="w", font="Arial",
             text=str(int(t)))

        if GPIO.input(17) == 0:                        # PBoost LBO, battery crit low
#            print("lbo is low")
            subprocess.Popen(["shutdown", "now"])


    def Update_Fast():
                
        if GPIO.input(6) == 0:                             # button 1 pressed
            sleep(0.6)
            if GPIO.input(6) == 0:
#                print("1                       long Press")
                bl.set_brightness(40)
            else:
#               print("1 short press")
                temp = bl.get_actual_brightness()
                temp +=10
                bl.set_brightness(temp)
            sleep(0.5)
#        else:
#            print("1 Released")
     
        if GPIO.input(13) ==0:                         # button 2
            sleep(0.6)
            if GPIO.input(13) ==0:
#                print("2                       long Press")
                subprocess.Popen(["/usr/bin/amixer", "set", "PCM", "80%"])
            else:
#                print("2 short press")
                subprocess.Popen(["/usr/bin/amixer", "set", "PCM", "90%"])
            sleep(0.5)
#       else:
#            print("2 Released")
    
        if GPIO.input(19) ==0:                         # button 3
            sleep(0.6)
            if GPIO.input(19) ==0:
#                print("3                       long Press")
                path = "sudo /usr/bin/python3 /home/pi/TabDash.py" #- NEW USE HERE!!
#                os.system (path)

            else:
#                print("3 short press")
#                  subprocess.Popen(['matchbox-keyboard'])
                path = "matchbox-keyboard"
                os.system (path)
            sleep(0.5)
#       else:
#            print("3 Released")
#            print(" ")

        LoopCount += 1
        if LoopCount >= 10:
            LoopCount = 0
            Update_Slow()

        self.after(100, self.update_Fast)

  
    def Wifi(self):
        if wifi.get() == 0:
            path = "sudo rfkill block wifi"
        else:
            path = "sudo rfkill unblock wifi"
        os.system (path)
        
    def Amp(self):
        if amp.get() == 0:
            GPIO.output(16,GPIO.LOW)
        else:
            GPIO.output(16,GPIO.HIGH)
            
    def Dim(self):
        if dim.get() == 0:
            command = ['xprintidle']
            result = run(command, stdout=PIPE, stderr=PIPE, universal_newlines=True)
            sleep(1)
            idle = result.stdout

            dim_time = 60 # in seconds

            if int(idle) > (dim_time * 1000) and dimmed == 0:
                oBrite = bl.get_actual_brightness()      # save orig brightness
                bl.set_brightness(30)
                dimmed = 1

            elif dimmed == 1 and int(idle) < (dim_time * 1000) :
                bl.set_brightness(oBrite)
                dimmed = 0
    

def main(): 
    root = Tk()
    ex = Example()
    root.geometry("140x230+650+212")
    root.mainloop() 

if __name__ == '__main__':
    main() 


Any help greatly appreciated!
Thank you
Grant

gordon77
Posts: 4107
Joined: Sun Aug 05, 2012 3:12 pm

Re: Tkinter Dash

Sun Aug 25, 2019 3:44 pm

Does this work ?

Code: Select all

import tkinter as tk
from tkinter import *
import spidev
import os, sys
import RPi.GPIO as GPIO
from time import sleep
import subprocess
import rpi_backlight as bl
from subprocess import PIPE, run


GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
GPIO.setup(6, GPIO.IN,pull_up_down=GPIO.PUD_UP)    # button 1
GPIO.setup(13, GPIO.IN,pull_up_down=GPIO.PUD_UP)   # button 2
GPIO.setup(19, GPIO.IN,pull_up_down=GPIO.PUD_UP)   # button 3
GPIO.setup(17, GPIO.IN,pull_up_down=GPIO.PUD_UP)   # PowerBoost LBO, low when <3.2V
GPIO.setup(16,GPIO.OUT)                            # amp en
GPIO.output(16,GPIO.LOW)

spi = spidev.SpiDev()
spi.open(0,0)
spi.max_speed_hz = 500000
DEBUG = 0

dimmed = 0

def get_adc(channel):
        if ((channel > 1) or (channel < 0)):
                return -1

        r = spi.xfer2([1,(2+channel)<<6,0])
        ret = ((r[1]&31) << 6) + (r[2] >> 2)
        return ret


class Example(Frame):
    
    def __init__(self):
        super().__init__() 
        self.initUI()
        
    def initUI(self): 
        global canvas,wifi,amp, dim, LoopCount, dimmed
        self.master.title("Dash")
        self.pack(fill=BOTH, expand=1) 
        canvas = Canvas(self)
        canvas.create_rectangle(5, 5, 45, 105,
             outline="#000", fill="#fb0")
        canvas.create_rectangle(50, 5, 90, 105,
             outline="#000", fill="#f50")
        canvas.create_rectangle(95, 5, 135, 105,
             outline="#000", fill="#05f")
        canvas.create_text(22, 120, anchor="w", font="Arial",
             text="V      Chg      T")
        dim = tk.IntVar()
        amp = tk.IntVar()
        wifi = tk.IntVar()
        button1 = tk.Checkbutton(self.master, text="Dim OK", variable = dim, width = 5, command=self.Dim) 
        button1.place(x=20, y=140)
        button2 = tk.Checkbutton(self.master, text="Amp ON", variable = amp, width = 6, command=self.Amp) 
        button2.place(x=18, y=170)
        button3 = tk.Checkbutton(self.master, text="Wifi ON", variable = wifi, width = 5, command=self.Wifi) 
        button3.place(x=20, y=200)
        canvas.pack(fill=BOTH, expand=1)
        LoopCount = 0
        dimmed = 0
        self.Update_Fast()

    
    def Update_Slow(self):
        global canvas
        Beeped = 0
        A = get_adc(0)                                          # Volts bar
        V = A * 0.00484                  # scale ADC to volts
        canvas.create_rectangle(5, 5, 45, 105,
             outline="#000", fill="#fff")
        if V > 4:
                canvas.create_rectangle(5, 105, 45, 105-((V-2.8)*78),  # was 110
             outline="#000", fill="blue")
        elif V > 3.9:
                canvas.create_rectangle(5, 105, 45, 105-((V-2.8)*78),  # was 110
             outline="#000", fill="green")
        elif V > 3.8:
                canvas.create_rectangle(5, 105, 45, 105-((V-2.8)*78),  # was 110
             outline="#000", fill="yellow")
        elif V > 3.7:
                canvas.create_rectangle(5, 105, 45, 105-((V-2.8)*78),  # was 110
             outline="#000", fill="orange")
        else:
                canvas.create_rectangle(5, 105, 45, 105-((V-2.8)*78),  # was 110
             outline="#000", fill="red")
        canvas.create_text(8, 90, anchor="w", font="Arial",
             text=(" %1.2f" %V))

                                                          # beep if batt Volts low:-
        if V < 3.4 and not Beeped:
            Beeped = 1
            os.system('omxplayer /home/pi/Downloads/beep-01a.mp3')


        if V > 4.1:                                             # Charge bar
                C = 100
        elif V > 4.0:
                C = V * 100.0 - 310.0
        elif V > 3.65:
                C = V * 228.6 - 824.0
        elif V > 3.0:
                C = V * 15.0 - 44.75
        else:
                C = 0
        canvas.create_rectangle(50, 5, 90, 105,
             outline="#000", fill="#fff")
        if C > 80:
                canvas.create_rectangle(50, 105, 90, 105-C,
             outline="#000", fill="blue")
        elif C > 40:
                canvas.create_rectangle(50, 105, 90, 105-C,
             outline="#000", fill="green")
        elif C > 30:
                canvas.create_rectangle(50, 105, 90, 105-C,
             outline="#000", fill="yellow")
        elif C > 20:
                canvas.create_rectangle(50, 105, 90, 105-C,
             outline="#000", fill="orange")
        else:
                canvas.create_rectangle(50, 105, 90, 105-C,
             outline="#000", fill="red")
        canvas.create_text(60, 90, anchor="w", font="Arial",
             text=str(int(C)))
        
        f = open("/sys/class/thermal/thermal_zone0/temp", "r")      # Temperature bar
        t = int(f.readline ())/1000
        canvas.create_rectangle(95, 5, 135, 105,
             outline="#000", fill="#fff")
        if t < 35:
                canvas.create_rectangle(95, 105, 135, 105-t,
             outline="#000", fill="blue")
        elif t < 50:
                canvas.create_rectangle(95, 105, 135, 105-t,
             outline="#000", fill="green")
        elif t < 65:
                canvas.create_rectangle(95, 105, 135, 105-t,
             outline="#000", fill="yellow")
        elif t < 80:
                canvas.create_rectangle(95, 105, 135, 105-t,
             outline="#000", fill="orange")
        else:
                canvas.create_rectangle(95, 105, 135, 105-t,
             outline="#000", fill="red")
        canvas.create_text(106, 90, anchor="w", font="Arial",
             text=str(int(t)))

        if GPIO.input(17) == 0:                        # PBoost LBO, battery crit low
#            print("lbo is low")
            subprocess.Popen(["shutdown", "now"])
        self.after(10, self.Dim)


    def Update_Fast(self):
        global LoopCount       
        if GPIO.input(6) == 0:                             # button 1 pressed
            sleep(0.6)
            if GPIO.input(6) == 0:
#                print("1                       long Press")
                bl.set_brightness(40)
            else:
#               print("1 short press")
                temp = bl.get_actual_brightness()
                temp +=10
                bl.set_brightness(temp)
            sleep(0.5)
#        else:
#            print("1 Released")
     
        if GPIO.input(13) ==0:                         # button 2
            sleep(0.6)
            if GPIO.input(13) ==0:
#                print("2                       long Press")
                subprocess.Popen(["/usr/bin/amixer", "set", "PCM", "80%"])
            else:
#                print("2 short press")
                subprocess.Popen(["/usr/bin/amixer", "set", "PCM", "90%"])
            sleep(0.5)
#       else:
#            print("2 Released")
    
        if GPIO.input(19) ==0:                         # button 3
            sleep(0.6)
            if GPIO.input(19) ==0:
#                print("3                       long Press")
                path = "sudo /usr/bin/python3 /home/pi/TabDash.py" #- NEW USE HERE!!
#                os.system (path)

            else:
#                print("3 short press")
#                  subprocess.Popen(['matchbox-keyboard'])
                path = "matchbox-keyboard"
                os.system (path)
            sleep(0.5)
#       else:
#            print("3 Released")
#            print(" ")

        LoopCount += 1
        if LoopCount >= 10:
            LoopCount = 0
            self.after(10, self.Update_Slow)

        self.after(100, self.Update_Fast)

  
    def Wifi(self):
        if wifi.get() == 0:
            path = "sudo rfkill block wifi"
        else:
            path = "sudo rfkill unblock wifi"
        os.system (path)
        
    def Amp(self):
        if amp.get() == 0:
            GPIO.output(16,GPIO.LOW)
        else:
            GPIO.output(16,GPIO.HIGH)
            
    def Dim(self):
        global dimmed
        if dim.get() == 1:
            command = ['xprintidle']
            result = run(command, stdout=PIPE, stderr=PIPE, universal_newlines=True)
            sleep(1)
            idle = result.stdout

            dim_time = 60 # in seconds

            if int(idle) > (dim_time * 1000) and dimmed == 0:
                dimmed = 1
                oBrite = bl.get_actual_brightness()      # save orig brightness
                bl.set_brightness(30)

            elif dimmed == 1 and int(idle) < (dim_time * 1000) :
                dimmed = 0
                bl.set_brightness(oBrite)
                dimmed = 0
    

def main(): 
    root = Tk()
    ex = Example()
    root.geometry("140x230+650+212")
    root.mainloop() 

if __name__ == '__main__':
    main() 

Asymic
Posts: 29
Joined: Sun Jun 16, 2019 8:28 am

Re: Tkinter Dash

Sun Aug 25, 2019 4:38 pm

Hi Gordon,

Yes! Once again your speed and willingness to help is splendid! Thank you so much.

I will study in detail what you have done, and do some background reading on all this.

Thank you again,
Grant

Return to “Python”