5 comments

  1. Dear Stewart,

    I just wanted to thank you for the fantastic article in the MagPi. Articles like this are very inspiring and help us beginners to see the possibilities that exist in the world of the experienced!

    I have tried to expand on the code that you kindly published and would like some help if you can spare the time!
    1. Closing the programme is very difficult. I have created a button to .destroy()
    This successfully kills the Tkinter widget but the terminal window hangs and sometimes causes an issue with the Arduinio. This means I have to remove the Ardion USB and close the terminal window to get it working.

    2. I am trying to add a time and date label. I can get it to display once or by following the get_temp code lines I can get the label to update but it sits in the same place as the temp window. Please can you explain why the labels are placed in this place for I cannot see a .pack command for the temp label.
    How can I add my timeDate function and display somewhere else in the widget!!!!
    I tried adding anchor in the label.config but this seems to have no effect.
    Sorry for the additional work but I really want to learn and expand on the already great article you created.

    My code below…..

    #!/usr/bin/python
    
    import pyfirmata
    from Tkinter import *
    import time
    from datetime import datetime
    
    # create a new board header,
    # specify a serial port;
    # could be /dev/ttyusb0 for older Arduinos
    board = pyfirmata.Arduino('/dev/ttyACM0')
    
    # start an iterator thread so serial buffer doesn't overflow
    iter8 = pyfirmata.util.Iterator(board)
    iter8.start()
    
    # set up pins
    # A0 Input  LM35
    pin0 = board.get_pin('a:0:i')
    # D3 PWM Output (LED)
    pin3 = board.get_pin ('d:3:p')
    
    # IMPORTANT!  Discard first reads until A0 has something valid
    while pin0.read() is None:
    	pass
    
    def get_temp():
    	#LM35 reading is degrees C to label
    	label_text = "Temp: %6.1f C" % (
    		pin0.read() * 5 * 100)
    	label.config(text = label_text)
    	# reshedule after half a second
    	root.after(500, get_temp)
    
    def set_brightness(x):
    	# set LED
    	# Scale widget returns 0..100
    	# Pyfirma expects 0..1.0
    	pin3.write(float(x) / 100.0)
    
    def get_timeDate():
    	#get the time and date
    	label_text_time = (datetime.now().strftime('%b %d  %H:%M:%S\n'))
    	label.config(text = label_text_time)
    	root.after(500, get_timeDate)
    	
    
    def cleanup():
    	# clean up on exit
    	# and turn LED back off
    	pin3.write(0)
    	board.exit()
    
    # set up GUI
    root = Tk()
    #ensure cleanup() is called on exit
    root.wm_protocol("WM_DELETE_WINDOW",cleanup)
    
    #Exit button use '.destroy()' to quit window
    button = Button(root,
    		  command = lambda:root.destroy(),
    		  text = "Quit",
                      fg= "red")
    button.pack(side = BOTTOM)
    
    title=Label (root,
                   text="Indoor Temperature Reading",
    	       fg= "blue")
    title.pack(side=TOP)
    
    
    # draw a big slider for LED brightness
    scale = Scale(root,
    		command = set_brightness,
    		orient = HORIZONTAL,
    		length = 400,
    		label = 'Brightness')
    scale.pack(anchor = CENTER)
    
    # place label up against scale widget
    label = Label(root)
    label.pack(anchor = 'nw')
    
    # start temperature read loop
    root.after(500, get_temp)
    
    #start time and date loop
    root.after(500, get_timeDate)
    
    # run Tk event loop
    root.mainloop()
    
  2. Thanks for getting in touch. To your points:

    1) Yes, I find the program doesn’t quit cleanly sometimes. I think it’s the serial iterator thread getting hung up, but I can’t be sure.

    2) Your code was trying to put the time label into the temperature label widget. Under the label.pack(anchor='nw') code, I added two lines of code to my original program:

    timelabel = Label(root)
    timelabel.pack(anchor='nw')
    

    and I changed the get_temp function to read:

    def get_temp():                         # LM35 reading in °C to label
        selection = "Temperature: %6.1f °C" % (pin0.read() * 5 * 100)
        label.config(text = selection)
        timelabel_text_time = (datetime.now().strftime('%b %d  %H:%M:%S\n'))
        timelabel.config(text = timelabel_text_time)
        root.after(500, get_temp)           # reschedule after half second
    

    So the function isn’t quite just updating the temperature any more. Clean code? Maybe not. It works, though.

    Tk’s pack() geometry manager is weird. For anything more than a couple of widgets, I recommend grid(), which is much more logical.

  3. Hi Stewart,

    I have been working quite a bit with PyFirmata for my console-based command program and I also had been experiencing serial-port issues after exiting my PyFirmata programs. I’ve looked over several examples throughout the web and took at peek at the source as well and after reading the comment above, I think I may be able to offer some help on how I cleanly exit a PyFirmata script.
    There appears to be another overlooked/undocumented function that seems to ‘cleanly’ destory the board object and restore the serial port.
    I use the following line in my except: blocks just in case there is an error while troubleshooting and also before my destroy() calls so the USB port will be left tied up:

    board.exit() # properly exit pyfirmata board instance and restore serial port

    Hope this helps!

    Matt

Leave a comment

Your email address will not be published. Required fields are marked *