7 import gnome.gconf as gconf
10 #gobject.threads_init()
12 PATH="/apps/pedometerhomewidget"
13 COUNTER=PATH+"/counter"
20 class PedometerHomePlugin(hildondesktop.HomePluginItem):
23 #labels for current steps
24 labelsC = { "timer" : None, "count" : None, "dist" : None, "avgSpeed" : None }
26 #labels for all time steps
27 labelsT = { "timer" : None, "count" : None, "dist" : None, "avgSpeed" : None }
44 gtk.gdk.threads_init()
45 hildondesktop.HomePluginItem.__init__(self)
47 self.client = gconf.client_get_default()
49 self.totalCounter = self.client.get_int(COUNTER)
50 self.totalTime = self.client.get_int(TIMER)
51 self.mode = self.client.get_int(MODE)
52 self.height = self.client.get_int(HEIGHT)
53 self.unit = self.client.get_int(UNIT)
54 self.aspect = self.client.get_int(ASPECT)
56 self.client.set_int(COUNTER, 0)
57 self.client.set_int(TIMER, 0)
58 self.client.set_int(MODE, 0)
59 self.client.set_int(HEIGHT, 0)
60 self.client.set_int(UNIT, 0)
61 self.client.set_int(ASPECT, 0)
63 self.pedometer = PedoCounter(self.update_values)
64 self.pedometer.set_mode(self.mode)
65 self.pedometer.set_height(self.height)
67 self.button = gtk.Button("Start")
68 self.button.connect("clicked", self.button_clicked)
70 self.create_labels(self.labelsC)
71 self.create_labels(self.labelsT)
73 self.update_ui_values(self.labelsC, 0, 0)
74 self.update_ui_values(self.labelsT, self.totalTime, self.totalCounter)
76 mainHBox = gtk.HBox(spacing=1)
78 descVBox = gtk.VBox(spacing=1)
79 descVBox.add(gtk.Label())
80 descVBox.add(gtk.Label("Time:"))
81 descVBox.add(gtk.Label("Steps:"))
82 descVBox.add(gtk.Label("Distance:"))
83 descVBox.add(gtk.Label("Avg Speed:"))
85 currentVBox = gtk.VBox(spacing=1)
86 currentVBox.add(gtk.Label("Current"))
87 currentVBox.add(self.labelsC["timer"])
88 currentVBox.add(self.labelsC["count"])
89 currentVBox.add(self.labelsC["dist"])
90 currentVBox.add(self.labelsC["avgSpeed"])
91 self.currentBox = currentVBox
93 totalVBox = gtk.VBox(spacing=1)
94 totalVBox.add(gtk.Label("Total"))
95 totalVBox.add(self.labelsT["timer"])
96 totalVBox.add(self.labelsT["count"])
97 totalVBox.add(self.labelsT["dist"])
98 totalVBox.add(self.labelsT["avgSpeed"])
99 self.totalBox = totalVBox
101 mainHBox.add(self.button)
102 mainHBox.add(descVBox)
103 mainHBox.add(currentVBox)
104 mainHBox.add(totalVBox)
110 self.connect("unrealize", self.close_requested)
111 self.set_settings(True)
112 self.connect("show-settings", self.show_settings)
114 def create_labels(self, labels):
115 labels["timer"] = gtk.Label()
116 labels["count"] = gtk.Label()
117 labels["dist"] = gtk.Label()
118 labels["avgSpeed"] = gtk.Label()
120 def update_aspect(self):
122 self.currentBox.show_all()
123 self.totalBox.show_all()
124 elif self.aspect == 1:
125 self.currentBox.show_all()
126 self.totalBox.hide_all()
128 self.currentBox.hide_all()
129 self.totalBox.show_all()
131 def update_ui_values(self, labels, timer, steps):
132 def get_str_distance(meters):
135 return str(meters/1000) + " km"
137 return str(meters/1609.344) + " mi"
140 return str(meters) + " m"
142 return str(meters*3.2808) + " ft"
144 def get_avg_speed(timer, dist):
155 return "N/A " + suffix
156 speed = 1.0 *dist / timer
157 #convert from meters per second to km/h or mi/h
159 return "%.2f %s" % (speed, suffix)
162 hours = int(tdelta / 3600)
163 tdelta -= 3600 * hours
164 mins = int(tdelta / 60)
168 strtime = "%.2d:%.2d:%.2d" % ( hours, mins, secs)
170 labels["timer"].set_label(strtime)
171 labels["count"].set_label(str(steps))
173 dist = self.pedometer.get_distance(steps)
175 labels["dist"].set_label(get_str_distance(dist))
176 labels["avgSpeed"].set_label(get_avg_speed(timer, dist))
178 def update_current(self):
179 self.update_ui_values(self.labelsC, self.time, self.counter)
181 def update_total(self):
182 self.update_ui_values(self.labelsT, self.totalTime, self.totalCounter)
184 def show_settings(self, widget):
185 def reset_total_counter(arg):
186 widget.totalCounter = 0
188 widget.update_total()
189 hildon.hildon_banner_show_information(self,"None", "Total counter was resetted")
191 def selector_changed(selector, data):
192 widget.mode = selector.get_active(0)
193 widget.client.set_int(MODE, widget.mode)
195 def selectorH_changed(selector, data):
196 widget.height = selectorH.get_active(0)
197 widget.client.set_int(HEIGHT, widget.height)
199 def selectorUnit_changed(selector, data):
200 widget.unit = selectorUnit.get_active(0)
201 widget.client.set_int(UNIT, widget.unit)
202 widget.update_current()
203 widget.update_total()
205 def selectorUI_changed(selector, data):
206 widget.aspect = selectorUI.get_active(0)
207 widget.client.set_int(ASPECT, widget.aspect)
208 widget.update_aspect()
210 dialog = gtk.Dialog()
211 dialog.set_transient_for(self)
212 dialog.set_title("Settings")
214 dialog.add_button("OK", gtk.RESPONSE_OK)
215 button = hildon.Button(gtk.HILDON_SIZE_AUTO_WIDTH | gtk.HILDON_SIZE_FINGER_HEIGHT, hildon.BUTTON_ARRANGEMENT_VERTICAL)
216 button.set_title("Reset total counter")
217 button.set_alignment(0, 0.8, 1, 1)
218 button.connect("clicked", reset_total_counter)
220 selector = hildon.TouchSelector(text=True)
221 selector.set_column_selection_mode(hildon.TOUCH_SELECTOR_SELECTION_MODE_SINGLE)
222 selector.append_text("Walk")
223 selector.append_text("Run")
224 selector.connect("changed", selector_changed)
226 modePicker = hildon.PickerButton(gtk.HILDON_SIZE_AUTO_WIDTH | gtk.HILDON_SIZE_FINGER_HEIGHT, hildon.BUTTON_ARRANGEMENT_VERTICAL)
227 modePicker.set_alignment(0.0, 0.5, 1.0, 1.0)
228 modePicker.set_title("Select mode")
229 modePicker.set_selector(selector)
230 modePicker.set_active(widget.mode)
232 selectorH = hildon.TouchSelector(text=True)
233 selectorH.set_column_selection_mode(hildon.TOUCH_SELECTOR_SELECTION_MODE_SINGLE)
234 selectorH.append_text("< 1.50 m")
235 selectorH.append_text("1.50 - 1.65 m")
236 selectorH.append_text("1.66 - 1.80 m")
237 selectorH.append_text("1.81 - 1.95 m")
238 selectorH.append_text(" > 1.95 m")
239 selectorH.connect("changed", selectorH_changed)
241 heightPicker = hildon.PickerButton(gtk.HILDON_SIZE_AUTO_WIDTH | gtk.HILDON_SIZE_FINGER_HEIGHT, hildon.BUTTON_ARRANGEMENT_VERTICAL)
242 heightPicker.set_alignment(0.0, 0.5, 1.0, 1.0)
243 heightPicker.set_title("Select height")
244 heightPicker.set_selector(selectorH)
245 heightPicker.set_active(widget.height)
247 selectorUnit = hildon.TouchSelector(text=True)
248 selectorUnit.set_column_selection_mode(hildon.TOUCH_SELECTOR_SELECTION_MODE_SINGLE)
249 selectorUnit.append_text("Metric (km)")
250 selectorUnit.append_text("English (mi)")
251 selectorUnit.connect("changed", selectorUnit_changed)
253 unitPicker = hildon.PickerButton(gtk.HILDON_SIZE_AUTO_WIDTH | gtk.HILDON_SIZE_FINGER_HEIGHT, hildon.BUTTON_ARRANGEMENT_VERTICAL)
254 unitPicker.set_alignment(0.0, 0.5, 1.0, 1.0)
255 unitPicker.set_title("Units")
256 unitPicker.set_selector(selectorUnit)
257 unitPicker.set_active(widget.unit)
259 selectorUI = hildon.TouchSelector(text=True)
260 selectorUI = hildon.TouchSelector(text=True)
261 selectorUI.set_column_selection_mode(hildon.TOUCH_SELECTOR_SELECTION_MODE_SINGLE)
262 selectorUI.append_text("Show current + total")
263 selectorUI.append_text("Show only current")
264 selectorUI.append_text("Show only total")
265 selectorUI.connect("changed", selectorUI_changed)
267 UIPicker = hildon.PickerButton(gtk.HILDON_SIZE_AUTO_WIDTH | gtk.HILDON_SIZE_FINGER_HEIGHT, hildon.BUTTON_ARRANGEMENT_VERTICAL)
268 UIPicker.set_alignment(0.0, 0.5, 1.0, 1.0)
269 UIPicker.set_title("Widget aspect")
270 UIPicker.set_selector(selectorUI)
271 UIPicker.set_active(widget.aspect)
273 dialog.vbox.add(button)
274 dialog.vbox.add(modePicker)
275 dialog.vbox.add(heightPicker)
276 dialog.vbox.add(unitPicker)
277 dialog.vbox.add(UIPicker)
280 response = dialog.run()
281 hildon.hildon_banner_show_information(self, "None", "You have to Stop/Start the counter to apply the new settings")
284 def close_requested(self, widget):
285 if self.pedometer is None:
288 self.pedometer.request_stop()
289 if self.pedometer.isAlive():
290 self.pedometer.join()
292 def update_values(self, totalCurent, lastInterval):
293 self.totalCounter += lastInterval
294 self.counter = totalCurent
296 tdelta = time.time() - self.time - self.startTime
298 self.totalTime += tdelta
300 self.update_current()
303 def button_clicked(self, button):
304 print "button clicked"
306 if self.pedometer is not None and self.pedometer.isAlive():
308 self.pedometer.request_stop()
309 self.pedometer.join()
310 self.client.set_int(COUNTER, self.totalCounter)
311 self.client.set_int(TIMER, int(self.totalTime))
312 self.button.set_label("Start")
316 self.pedometer = PedoCounter(self.update_values)
317 self.pedometer.set_mode(self.mode)
318 self.pedometer.set_height(self.height)
323 self.update_current()
325 self.pedometer.start()
326 self.startTime = time.time()
327 self.button.set_label("Stop")
329 print "button clicked finished"
331 hd_plugin_type = PedometerHomePlugin
333 # The code below is just for testing purposes.
334 # It allows to run the widget as a standalone process.
335 if __name__ == "__main__":
337 gobject.type_register(hd_plugin_type)
338 obj = gobject.new(hd_plugin_type, plugin_id="plugin_id")
342 ############### old pedometer.py ###
346 from threading import Thread
348 logger = logging.getLogger("pedometer")
349 logger.setLevel(logging.INFO)
351 ch = logging.StreamHandler()
352 formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
353 ch.setFormatter(formatter)
354 logger.addHandler(ch)
356 class PedoIntervalCounter:
364 #TODO: check if last detected step is at the end of the interval
366 def __init__(self, coords, tval):
372 def setThreshold(self, value):
373 self.MIN_THRESHOLD = value
375 def setTimeSteps(self, value):
376 self.MIN_TIME_STEPS = value
378 def calc_mean(self, vals):
383 return sum / len(vals)
386 def calc_stdev(self, vals):
388 mean = self.calc_mean(vals)
390 rez+=pow(abs(mean-i),2)
391 return math.sqrt(rez/len(vals))
393 def calc_threshold(self, vals):
396 mean = self.calc_mean(vals)
397 threshold = max (abs(mean-vmax), abs(mean-vmin))
400 def count_steps(self, vals, t):
401 threshold = self.MIN_THRESHOLD
402 mean = self.calc_mean(vals)
407 if abs(vals[i] - mean) > threshold:
410 while i < len(vals) and t[i] < ntime:
415 def get_best_values(self, x, y, z):
416 dev1 = self.calc_stdev(x)
417 dev2 = self.calc_stdev(y)
418 dev3 = self.calc_stdev(z)
419 dev_max = max(dev1, dev2, dev3)
421 if ( abs(dev1 - dev_max ) < 0.001):
422 logger.info("X chosen as best axis, stdev %f" % dev1)
424 elif (abs(dev2 - dev_max) < 0.001):
425 logger.info("Y chosen as best axis, stdev %f" % dev2)
428 logger.info("Z chosen as best axis, stdev %f" % dev3)
431 def number_steps(self):
432 vals = self.get_best_values(self.x, self.y, self.z)
433 return self.count_steps(vals, self.t)
435 class PedoCounter(Thread):
436 COORD_FNAME = "/sys/class/i2c-adapter/i2c-3/3-001d/coord"
437 COORD_FNAME_SDK = "/home/andrei/pedometer-widget-0.1/date.txt"
438 COORD_GET_INTERVAL = 0.01
447 stop_requested = False
448 update_function = None
450 def __init__(self, update_function = None):
451 Thread.__init__(self)
452 if not os.path.exists(self.COORD_FNAME):
453 self.COORD_FNAME = self.COORD_FNAME_SDK
455 self.update_function = update_function
457 def set_mode(self, mode):
458 #runnig, higher threshold to prevent fake steps
460 self.MIN_THRESHOLD = 600
461 self.MIN_TIME_STEPS = 0.35
464 self.MIN_THRESHOLD = 500
465 self.MIN_TIME_STEPS = 0.5
467 #set height, will affect the distance
468 def set_height(self, height_interval):
469 if height_interval == 0:
471 elif height_interval == 1:
473 elif height_interval == 2:
475 elif height_interval == 3:
477 elif height_interval == 4:
480 def get_rotation(self):
481 f = open(self.COORD_FNAME, 'r')
482 coords = [int(w) for w in f.readline().split()]
486 def reset_counter(self):
489 def get_counter(self):
492 def start_interval(self):
493 logger.info("New interval started")
496 coords = [[], [], []]
497 while not self.stop_requested and (len(t) == 0 or t[-1] < 5):
498 x,y,z = self.get_rotation()
499 coords[0].append(int(x))
500 coords[1].append(int(y))
501 coords[2].append(int(z))
502 now = time.time()-stime
504 time.sleep(self.COORD_GET_INTERVAL)
505 pic = PedoIntervalCounter(coords, t)
506 cnt = pic.number_steps()
508 logger.info("Number of steps detected for last interval %d, number of coords: %d" % (cnt, len(t)))
511 logger.info("Total number of steps : %d" % self.counter)
514 def request_stop(self):
515 self.stop_requested = True
518 logger.info("Thread started")
519 while 1 and not self.stop_requested:
520 last_cnt = self.start_interval()
521 if self.update_function is not None:
522 gobject.idle_add(self.update_function, self.counter, last_cnt)
524 logger.info("Thread has finished")
526 def get_distance(self, steps=None):
529 return self.STEP_LENGTH * steps;