#!/usr/bin/env python # ------------------------------------------------------------------------ # DigiTemp Python Graphing Application # Copyright 2003 by Brian C. Lane <bcl@brianlane.com> # All Rights Reserved # # Released under GPL v2.0 # # ==============================[ History ]=============================== # 07/11/2003 Need to catch a resize event so I an recalculate the scale # bcl for the display. # Still don't know how to scroll. # drawing is documented here: # http://www.gnome.org/~james/pygtk-docs/class-gdkdrawable.html # # How do I get a gc without a widget so I can draw on the # pixmap? And so I can copy it to scroll it left or right. # # 07/10/2003 It is now reading temperatures. It still needs to be able # bcl to check the return value from DigiTemp for errors. # I need to add plotting of temps and scrolling of the graph # next. # Eventually there will be a menu of sensors and dialog boxes # to let the user enter descriptive names for the sensors, # and assign colors and alarms. # # 06/20/2003 I have timers working, need overlaying pixmaps and getting # bcl temperatures from DigiTemp. # How do I draw one image over another, with transparency? # Also need to catch resize events and redraw. Hmm, which # means that I need to keep track of a screen's worth of # datapoints. # If it has to restart when resized that isn't too bad, I # can always change that later. # ----------------------------------------------------------------------- # Old notes: # # I think I can draw with this, but how do I hook up other events, like a # timer to go and read temperatures every 10 seconds or whenever? # Really ought to be multi-threaded. # Python has a thread module too... Need to look into it later # Need a routine to draw the background for the graph, based on the canvas # size and range of temperatures to display. # Need to use 2 pixmaps, one for the graph and one for the background. The # graph pixmap will get scrolled to the right or left and then overlaied # onto the background (using a transparent color). import string, os, sys, time, gtk bg_pixmap = None pixmap = None readtemp_timer = 0 dt = {} # Default temperature limits of the pixmap in Centigrade graph_min = -10 graph_max = 60 # Initalize the 1-wire network, print out whatever it says def init_1wire(): cmd = "/home/bcl/digitemp/digitemp -s/dev/ttyUSB0 -i -q -o\"T %R %N %.2C\" -O\"C %R %N %n %C\"" for outline in os.popen(cmd).readlines(): outline = outline[:-1]; print outline # Ought to be able to check return code for success/failure # Read all attached sensors def read_sensors(): cmd = "/home/bcl/digitemp/digitemp -a -q -o1" for outline in os.popen(cmd).readlines(): outline = outline[:-1] # print outline S = string.split( outline, " " ) if S[0] == 'T': # Add the temperature reading to a dictionary dt[S[1]] = S[3] if S[0] == 'C': # Add the counter reading to a dictionary dt[S[1]] = S[3] return 1 # Plot a new temperature point on the graph # Scroll the graph the right direction and add the new plot def plottemp( centigrade ): global pixmap # Get the current image width and height (width, height) = pixmap.get_size() # Scroll the image to the left image = pixmap.get_image( 1,0,width-1,height) pixmap.draw_image( gc, image, 0, 0, width-1, height, 0, 0, width-1, height ) # Read the temperature from the attached DigiTemp system # and plot the new temperatures def readtemp( ): global readtemp_timer if( read_sensors() == 1 ): for sensor in dt: print dt[sensor] plottemp( dt[sensor] ) # Restart the timer readtemp_timer = gtk.timeout_add( 1000, readtemp) # Draw a graph on the background def draw_graph_bg(): global pixmap # Draw the initial window? def configure_event(widget, event): global pixmap win = widget.window width, height = win.get_size() # Create the graph pixmap pixmap = gtk.gdk.Pixmap(win, width, height) pixmap.draw_rectangle(widget.get_style().white_gc, gtk.TRUE, 0, 0, width, height) # Create the background pixmap bg_pixmap = gtk.gdk.Pixmap(win, width, height) draw_graph_bg() return gtk.TRUE def expose_event(widget, event): x, y, width, height = event.area gc = widget.get_style().fg_gc[gtk.STATE_NORMAL] widget.window.draw_drawable(gc, pixmap, x, y, x, y, width, height) return gtk.FALSE # Draw something on the display def draw_brush(widget, x, y): rect = (x-5, y-5, 10, 10) pixmap.draw_rectangle(widget.get_style().black_gc, gtk.TRUE, x-5, y-5, 10, 10) widget.queue_draw() def main(): if( init_1wire() == 0 ): print "1-wire initialization failed\n"; exit; win = gtk.Window() win.set_name("DigiTemp Realtime Graph") win.connect("destroy", gtk.mainquit) win.set_border_width(5) vbox = gtk.VBox(spacing=3) win.add(vbox) vbox.show() drawing_area = gtk.DrawingArea() drawing_area.set_size_request(400, 150) vbox.pack_start(drawing_area) drawing_area.show() drawing_area.connect("expose_event", expose_event) drawing_area.connect("configure_event", configure_event) drawing_area.set_events(gtk.gdk.EXPOSURE_MASK ) button = gtk.Button("Quit") vbox.pack_start(button, expand=gtk.FALSE, fill=gtk.FALSE) button.connect("clicked", lambda widget, win=win: win.destroy()) button.show() win.show() # Read the temperatures in 1 second readtemp_timer = gtk.timeout_add( 1000, readtemp) gtk.main() if __name__ == '__main__': main()