7 import gnome.gconf as gconf
10 #gobject.threads_init()
12 PATH="/apps/pedometerhomewidget"
13 COUNTER=PATH+"/counter"
19 LOGGING=PATH+"/logging"
21 class PedometerHomePlugin(hildondesktop.HomePluginItem):
24 #labels for current steps
25 labelsC = { "timer" : None, "count" : None, "dist" : None, "avgSpeed" : None }
27 #labels for all time steps
28 labelsT = { "timer" : None, "count" : None, "dist" : None, "avgSpeed" : None }
46 gtk.gdk.threads_init()
47 hildondesktop.HomePluginItem.__init__(self)
49 self.client = gconf.client_get_default()
51 self.totalCounter = self.client.get_int(COUNTER)
52 self.totalTime = self.client.get_int(TIMER)
53 self.mode = self.client.get_int(MODE)
54 self.height = self.client.get_int(HEIGHT)
55 self.unit = self.client.get_int(UNIT)
56 self.aspect = self.client.get_int(ASPECT)
57 self.logging = self.client.get_bool(LOGGING)
59 self.client.set_int(COUNTER, 0)
60 self.client.set_int(TIMER, 0)
61 self.client.set_int(MODE, 0)
62 self.client.set_int(HEIGHT, 0)
63 self.client.set_int(UNIT, 0)
64 self.client.set_int(ASPECT, 0)
65 self.client.set_bool(LOGGING, False)
67 self.pedometer = PedoCounter(self.update_values)
68 self.pedometer.set_mode(self.mode)
69 self.pedometer.set_height(self.height)
71 self.button = gtk.Button("Start")
72 self.button.connect("clicked", self.button_clicked)
74 self.create_labels(self.labelsC)
75 self.create_labels(self.labelsT)
77 self.update_ui_values(self.labelsC, 0, 0)
78 self.update_ui_values(self.labelsT, self.totalTime, self.totalCounter)
80 mainHBox = gtk.HBox(spacing=1)
82 descVBox = gtk.VBox(spacing=1)
83 descVBox.add(gtk.Label())
84 descVBox.add(gtk.Label("Time:"))
85 descVBox.add(gtk.Label("Steps:"))
86 descVBox.add(gtk.Label("Distance:"))
87 descVBox.add(gtk.Label("Avg Speed:"))
89 currentVBox = gtk.VBox(spacing=1)
90 currentVBox.add(gtk.Label("Current"))
91 currentVBox.add(self.labelsC["timer"])
92 currentVBox.add(self.labelsC["count"])
93 currentVBox.add(self.labelsC["dist"])
94 currentVBox.add(self.labelsC["avgSpeed"])
95 self.currentBox = currentVBox
97 totalVBox = gtk.VBox(spacing=1)
98 totalVBox.add(gtk.Label("Total"))
99 totalVBox.add(self.labelsT["timer"])
100 totalVBox.add(self.labelsT["count"])
101 totalVBox.add(self.labelsT["dist"])
102 totalVBox.add(self.labelsT["avgSpeed"])
103 self.totalBox = totalVBox
105 mainHBox.add(self.button)
106 mainHBox.add(descVBox)
107 mainHBox.add(currentVBox)
108 mainHBox.add(totalVBox)
110 self.mainhbox = mainHBox
116 self.connect("unrealize", self.close_requested)
117 self.set_settings(True)
118 self.connect("show-settings", self.show_settings)
120 def create_labels(self, labels):
121 labels["timer"] = gtk.Label()
122 labels["count"] = gtk.Label()
123 labels["dist"] = gtk.Label()
124 labels["avgSpeed"] = gtk.Label()
126 def update_aspect(self):
128 self.currentBox.show_all()
129 self.totalBox.show_all()
130 elif self.aspect == 1:
131 self.currentBox.show_all()
132 self.totalBox.hide_all()
134 self.currentBox.hide_all()
135 self.totalBox.show_all()
137 def update_ui_values(self, labels, timer, steps):
138 def get_str_distance(meters):
141 return "%.2f km" % (meters/1000)
143 return "%.2f mi" % (meters/1609.344)
146 return "%d m" % meters
148 return "%d ft" % int(meters*3.2808)
150 def get_avg_speed(timer, dist):
161 return "N/A " + suffix
162 speed = 1.0 *dist / timer
163 #convert from meters per second to km/h or mi/h
165 return "%.2f %s" % (speed, suffix)
168 hours = int(tdelta / 3600)
169 tdelta -= 3600 * hours
170 mins = int(tdelta / 60)
174 strtime = "%.2d:%.2d:%.2d" % ( hours, mins, secs)
176 labels["timer"].set_label(strtime)
177 labels["count"].set_label(str(steps))
179 dist = self.pedometer.get_distance(steps)
181 labels["dist"].set_label(get_str_distance(dist))
182 labels["avgSpeed"].set_label(get_avg_speed(timer, dist))
184 def update_current(self):
185 self.update_ui_values(self.labelsC, self.time, self.counter)
187 def update_total(self):
188 self.update_ui_values(self.labelsT, self.totalTime, self.totalCounter)
190 def show_settings(self, widget):
191 def reset_total_counter(arg):
192 widget.totalCounter = 0
194 widget.update_total()
195 hildon.hildon_banner_show_information(self,"None", "Total counter was resetted")
197 def selector_changed(selector, data):
198 widget.mode = selector.get_active(0)
199 widget.client.set_int(MODE, widget.mode)
201 def selectorH_changed(selector, data):
202 widget.height = selectorH.get_active(0)
203 widget.client.set_int(HEIGHT, widget.height)
205 def selectorUnit_changed(selector, data):
206 widget.unit = selectorUnit.get_active(0)
207 widget.client.set_int(UNIT, widget.unit)
208 widget.update_current()
209 widget.update_total()
211 def selectorUI_changed(selector, data):
212 widget.aspect = selectorUI.get_active(0)
213 widget.client.set_int(ASPECT, widget.aspect)
214 widget.update_aspect()
216 def logButton_changed(checkButton):
217 widget.logging = checkButton.get_active()
220 widget.client.set_bool(LOGGING, widget.logging)
222 dialog = gtk.Dialog()
223 dialog.set_transient_for(self)
224 dialog.set_title("Settings")
226 dialog.add_button("OK", gtk.RESPONSE_OK)
227 button = hildon.Button(gtk.HILDON_SIZE_AUTO_WIDTH | gtk.HILDON_SIZE_FINGER_HEIGHT, hildon.BUTTON_ARRANGEMENT_VERTICAL)
228 button.set_title("Reset total counter")
229 button.set_alignment(0, 0.8, 1, 1)
230 button.connect("clicked", reset_total_counter)
232 selector = hildon.TouchSelector(text=True)
233 selector.set_column_selection_mode(hildon.TOUCH_SELECTOR_SELECTION_MODE_SINGLE)
234 selector.append_text("Walk")
235 selector.append_text("Run")
236 selector.connect("changed", selector_changed)
238 modePicker = hildon.PickerButton(gtk.HILDON_SIZE_AUTO_WIDTH | gtk.HILDON_SIZE_FINGER_HEIGHT, hildon.BUTTON_ARRANGEMENT_VERTICAL)
239 modePicker.set_alignment(0.0, 0.5, 1.0, 1.0)
240 modePicker.set_title("Select mode")
241 modePicker.set_selector(selector)
242 modePicker.set_active(widget.mode)
244 selectorH = hildon.TouchSelector(text=True)
245 selectorH.set_column_selection_mode(hildon.TOUCH_SELECTOR_SELECTION_MODE_SINGLE)
246 selectorH.append_text("< 1.50 m")
247 selectorH.append_text("1.50 - 1.65 m")
248 selectorH.append_text("1.66 - 1.80 m")
249 selectorH.append_text("1.81 - 1.95 m")
250 selectorH.append_text(" > 1.95 m")
251 selectorH.connect("changed", selectorH_changed)
253 heightPicker = hildon.PickerButton(gtk.HILDON_SIZE_AUTO_WIDTH | gtk.HILDON_SIZE_FINGER_HEIGHT, hildon.BUTTON_ARRANGEMENT_VERTICAL)
254 heightPicker.set_alignment(0.0, 0.5, 1.0, 1.0)
255 heightPicker.set_title("Select height")
256 heightPicker.set_selector(selectorH)
257 heightPicker.set_active(widget.height)
259 selectorUnit = hildon.TouchSelector(text=True)
260 selectorUnit.set_column_selection_mode(hildon.TOUCH_SELECTOR_SELECTION_MODE_SINGLE)
261 selectorUnit.append_text("Metric (km)")
262 selectorUnit.append_text("English (mi)")
263 selectorUnit.connect("changed", selectorUnit_changed)
265 unitPicker = hildon.PickerButton(gtk.HILDON_SIZE_AUTO_WIDTH | gtk.HILDON_SIZE_FINGER_HEIGHT, hildon.BUTTON_ARRANGEMENT_VERTICAL)
266 unitPicker.set_alignment(0.0, 0.5, 1.0, 1.0)
267 unitPicker.set_title("Units")
268 unitPicker.set_selector(selectorUnit)
269 unitPicker.set_active(widget.unit)
271 selectorUI = hildon.TouchSelector(text=True)
272 selectorUI = hildon.TouchSelector(text=True)
273 selectorUI.set_column_selection_mode(hildon.TOUCH_SELECTOR_SELECTION_MODE_SINGLE)
274 selectorUI.append_text("Show current + total")
275 selectorUI.append_text("Show only current")
276 selectorUI.append_text("Show only total")
277 selectorUI.connect("changed", selectorUI_changed)
279 UIPicker = hildon.PickerButton(gtk.HILDON_SIZE_AUTO_WIDTH | gtk.HILDON_SIZE_FINGER_HEIGHT, hildon.BUTTON_ARRANGEMENT_VERTICAL)
280 UIPicker.set_alignment(0.0, 0.5, 1.0, 1.0)
281 UIPicker.set_title("Widget aspect")
282 UIPicker.set_selector(selectorUI)
283 UIPicker.set_active(widget.aspect)
285 logButton = hildon.CheckButton(gtk.HILDON_SIZE_AUTO_WIDTH | gtk.HILDON_SIZE_FINGER_HEIGHT)
286 logButton.set_label("Log data")
287 logButton.set_active(widget.logging)
288 logButton.connect("toggled", logButton_changed)
290 dialog.vbox.add(button)
291 dialog.vbox.add(modePicker)
292 dialog.vbox.add(heightPicker)
293 dialog.vbox.add(unitPicker)
294 dialog.vbox.add(UIPicker)
295 dialog.vbox.add(logButton)
298 response = dialog.run()
299 hildon.hildon_banner_show_information(self, "None", "You have to Stop/Start the counter to apply the new settings")
302 def close_requested(self, widget):
303 if self.pedometer is None:
306 self.pedometer.request_stop()
307 if self.pedometer.isAlive():
308 self.pedometer.join()
310 def update_values(self, totalCurent, lastInterval):
311 self.totalCounter += lastInterval
312 self.counter = totalCurent
314 tdelta = time.time() - self.time - self.startTime
316 self.totalTime += tdelta
318 self.update_current()
321 def button_clicked(self, button):
322 print "button clicked"
324 if self.pedometer is not None and self.pedometer.isAlive():
326 self.pedometer.request_stop()
327 self.pedometer.join()
328 self.client.set_int(COUNTER, self.totalCounter)
329 self.client.set_int(TIMER, int(self.totalTime))
330 self.button.set_label("Start")
332 self.pedometer = PedoCounter(self.update_values)
333 self.pedometer.set_mode(self.mode)
334 self.pedometer.set_height(self.height)
335 self.pedometer.set_logging(self.logging)
340 self.update_current()
342 self.pedometer.start()
343 self.startTime = time.time()
344 self.button.set_label("Stop")
346 print "button clicked finished"
348 hd_plugin_type = PedometerHomePlugin
350 # The code below is just for testing purposes.
351 # It allows to run the widget as a standalone process.
352 if __name__ == "__main__":
354 gobject.type_register(hd_plugin_type)
355 obj = gobject.new(hd_plugin_type, plugin_id="plugin_id")
359 ############### old pedometer.py ###
363 from threading import Thread
365 logger = logging.getLogger("pedometer")
366 logger.setLevel(logging.INFO)
368 ch = logging.StreamHandler()
369 formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
370 ch.setFormatter(formatter)
371 logger.addHandler(ch)
373 class PedoIntervalCounter:
381 #TODO: check if last detected step is at the end of the interval
383 def __init__(self, coords, tval):
389 def setThreshold(self, value):
390 self.MIN_THRESHOLD = value
392 def setTimeSteps(self, value):
393 self.MIN_TIME_STEPS = value
395 def calc_mean(self, vals):
400 return sum / len(vals)
403 def calc_stdev(self, vals):
405 mean = self.calc_mean(vals)
407 rez+=pow(abs(mean-i),2)
408 return math.sqrt(rez/len(vals))
410 def calc_threshold(self, vals):
413 mean = self.calc_mean(vals)
414 threshold = max (abs(mean-vmax), abs(mean-vmin))
417 def count_steps(self, vals, t):
418 threshold = self.MIN_THRESHOLD
419 mean = self.calc_mean(vals)
424 if abs(vals[i] - mean) > threshold:
427 while i < len(vals) and t[i] < ntime:
432 def get_best_values(self, x, y, z):
433 dev1 = self.calc_stdev(x)
434 dev2 = self.calc_stdev(y)
435 dev3 = self.calc_stdev(z)
436 dev_max = max(dev1, dev2, dev3)
438 if ( abs(dev1 - dev_max ) < 0.001):
439 logger.info("X chosen as best axis, stdev %f" % dev1)
441 elif (abs(dev2 - dev_max) < 0.001):
442 logger.info("Y chosen as best axis, stdev %f" % dev2)
445 logger.info("Z chosen as best axis, stdev %f" % dev3)
448 def number_steps(self):
449 vals = self.get_best_values(self.x, self.y, self.z)
450 return self.count_steps(vals, self.t)
452 class PedoCounter(Thread):
453 COORD_FNAME = "/sys/class/i2c-adapter/i2c-3/3-001d/coord"
454 COORD_FNAME_SDK = "/home/andrei/pedometer-widget-0.1/date.txt"
455 LOGFILE = "/home/user/log_pedometer"
456 COORD_GET_INTERVAL = 0.01
465 stop_requested = False
466 update_function = None
469 def __init__(self, update_function = None):
470 Thread.__init__(self)
471 if not os.path.exists(self.COORD_FNAME):
472 self.COORD_FNAME = self.COORD_FNAME_SDK
474 self.update_function = update_function
476 def set_mode(self, mode):
477 #runnig, higher threshold to prevent fake steps
479 self.MIN_THRESHOLD = 650
480 self.MIN_TIME_STEPS = 0.35
483 self.MIN_THRESHOLD = 500
484 self.MIN_TIME_STEPS = 0.5
486 def set_logging(self, value):
489 #set height, will affect the distance
490 def set_height(self, height_interval):
491 if height_interval == 0:
493 elif height_interval == 1:
495 elif height_interval == 2:
497 elif height_interval == 3:
499 elif height_interval == 4:
502 def get_rotation(self):
503 f = open(self.COORD_FNAME, 'r')
504 coords = [int(w) for w in f.readline().split()]
508 def reset_counter(self):
511 def get_counter(self):
514 def start_interval(self):
515 logger.info("New interval started")
518 coords = [[], [], []]
519 while not self.stop_requested and (len(t) == 0 or t[-1] < 5):
520 x,y,z = self.get_rotation()
521 coords[0].append(int(x))
522 coords[1].append(int(y))
523 coords[2].append(int(z))
524 now = time.time()-stime
526 self.file.write("%d %d %d %f\n" %(coords[0][-1], coords[1][-1], coords[2][-1], now))
529 time.sleep(self.COORD_GET_INTERVAL)
530 pic = PedoIntervalCounter(coords, t)
531 cnt = pic.number_steps()
533 logger.info("Number of steps detected for last interval %d, number of coords: %d" % (cnt, len(t)))
536 logger.info("Total number of steps : %d" % self.counter)
539 def request_stop(self):
540 self.stop_requested = True
543 logger.info("Thread started")
546 fname = "%d_%d_%d_%d_%d_%d" % time.localtime()[0:6]
547 self.file = open(self.LOGFILE + fname + ".txt", "w")
549 while 1 and not self.stop_requested:
550 last_cnt = self.start_interval()
551 if self.update_function is not None:
552 gobject.idle_add(self.update_function, self.counter, last_cnt)
557 logger.info("Thread has finished")
559 def get_distance(self, steps=None):
562 return self.STEP_LENGTH * steps;