diff --git a/main.kv b/main.kv index f533aa0..fba4656 100644 --- a/main.kv +++ b/main.kv @@ -1,6 +1,8 @@ : text: 'Current Temperature: n/a' -# on_lastTemperature: self.update_current_temperature_label() + +: + allow_stretch: True : label_wid: "Temperature Monitor" @@ -17,5 +19,5 @@ text: 'No File Chosen' Label: text: 'Data Source' - Label: - text: 'Graph placeholder' + PlotWidget: + id: 'mainplot' \ No newline at end of file diff --git a/main.py b/main.py index b681894..9ac22b2 100644 --- a/main.py +++ b/main.py @@ -1,13 +1,23 @@ import kivy from kivy.app import App from kivy.clock import Clock +import kivy.core.image +from kivy.core.image.img_pygame import ImageLoaderPygame +import kivy.graphics.texture from kivy.logger import Logger -from kivy.properties import ObjectProperty, StringProperty +from kivy.properties import ListProperty, NumericProperty, ObjectProperty, StringProperty from kivy.uix.boxlayout import BoxLayout from kivy.uix.floatlayout import FloatLayout +from kivy.uix.image import Image from kivy.uix.label import Label import kivy.lang +import numpy +import matplotlib +matplotlib.use('Agg') +import matplotlib.image +import matplotlib.pyplot import Queue +import StringIO import temp_log import threading @@ -36,7 +46,8 @@ class MainApp(App): class MainWindow(FloatLayout): """Main Window class""" dataSource = StringProperty('/dev/ttyACM0') - lastTemperature = StringProperty('n/a') + lastTemperature = NumericProperty(-1000.) + lastTime = NumericProperty(-1.) def update_last_temperature(self, dt): global dataThreadDataQueue @@ -44,20 +55,48 @@ class MainWindow(FloatLayout): try: data = dataThreadDataQueue.get_nowait() if data is not None: - self.lastTemperature = str(data['data']['temperature']) + Logger.debug('Data: ' + str(data)) + if 'data' in data and 'temperature' in data['data']: + self.lastTemperature = float(data['data']['temperature']) + if 'time' in data: + self.lastTime = float(data['time']) except Queue.Empty: pass + def on_lastTemperature(self, instance, value): Logger.debug('lastTemperature has changed to: ' + str(value)) children = self.children[:] while children: child = children.pop() + children.extend(child.children) + if child is self: + continue try: child.on_lastTemperature(instance, value) - except Exception, e: + #Logger.debug('Called on_lastTemperature for child: ' + str(child)) + except AttributeError: pass + except Exception, e: + Logger.exception(str(e)) + + + def on_lastTime(self, instance, value): + Logger.debug('lastTime has changed to: ' + str(value)) + children = self.children[:] + while children: + child = children.pop() children.extend(child.children) + if child is self: + continue + #Logger.debug(str(child)) + try: + child.on_lastTime(instance, value) + #Logger.debug('Called on_lastTime for child: ' + str(child)) + except AttributeError, e: + pass + except Exception, e: + Logger.exception(str(e)) class MyLabel(Label): @@ -66,6 +105,65 @@ class MyLabel(Label): self.text = 'Current temperature: ' + str(value) +class PlotWidget(Image): + + def __init__(self, **kwargs): + super(Image, self).__init__(**kwargs) + self.data = numpy.array([], dtype=float); + self.lastTime = 0 + self.lastTemperature = 0 + self.figure = matplotlib.pyplot.figure() + self.plot_axes = self.figure.add_subplot(1, 1, 1) + self.plot_axes.hold(False) + self.plot_axes.set_ylabel('Temperature (deg C)') + self.plot_axes.set_xlabel('Time') + self.plot_axes.set_title('Recorded Temperature') + + + def update(self): + if not self.data.any(): + return + #Logger.debug('self.data: ' + str(self.data)) + #Logger.debug('self.data shape: ' + str(self.data.shape)) + data = numpy.copy(self.data) + data = data.transpose() + #Logger.debug('transpoed data: ' + str(data)) + #Logger.debug('transposed data shape: ' + str(data.shape)) + t, temperature = numpy.split(data, 2, axis = 0) + #Logger.debug('time: ' + str(t[0])) + #Logger.debug('temperature: ' + str(temperature[0])) + self.plot_axes.plot(t[0], temperature[0]) + image_data = StringIO.StringIO() + self.figure.savefig(image_data, format = 'png') + image_data.seek(0) + self.texture = ImageLoaderPygame(image_data, nocache = True).texture + + + def on_lastTemperature(self, instance, value): + self.lastTemperature = value + self.update_data() + + + def on_lastTime(self, instance, value): + self.lastTime = value + self.update_data() + + + def update_data(self): + if self.lastTime == 0 or self.lastTemperature == 0: + return + newpoint = numpy.array([(self.lastTime, self.lastTemperature)], dtype=float, ndmin = 2) + if not self.data.any(): + self.data = newpoint + return + #Logger.debug('self.data: ' + str(self.data)) + #Logger.debug('newpoint: ' + str(newpoint)) + self.data = numpy.vstack((self.data, newpoint)) + self.update() + #self.data = numpy.concatenate((self.data, newpoint), axis = 0) + #self.data = numpy.copy(self.data) # This will cause ObjectProperty to fire a change event + + if __name__ == '__main__': dataThread = threading.Thread(None, temp_log.threaded_reader, None, ['/dev/ttyACM0', dataThreadDataQueue, dataThreadCommandQueue]) MainApp().run()