From: <jb...@us...> - 2009-10-12 07:34:30
|
Revision: 365 http://pytrainer.svn.sourceforge.net/pytrainer/?rev=365&view=rev Author: jblance Date: 2009-10-12 07:34:20 +0000 (Mon, 12 Oct 2009) Log Message: ----------- Update to garmin-hr in plugin branch Modified Paths: -------------- pytrainer/branches/plugins-v2/plugins/garmin-hr/conf.xml Added Paths: ----------- pytrainer/branches/plugins-v2/plugins/garmin-hr/garminhr.py pytrainer/branches/plugins-v2/plugins/garmin-hr/translate.xsl Removed Paths: ------------- pytrainer/branches/plugins-v2/plugins/garmin-hr/gtrnctr2gpx.py pytrainer/branches/plugins-v2/plugins/garmin-hr/main.py Modified: pytrainer/branches/plugins-v2/plugins/garmin-hr/conf.xml =================================================================== --- pytrainer/branches/plugins-v2/plugins/garmin-hr/conf.xml 2009-10-11 08:31:03 UTC (rev 364) +++ pytrainer/branches/plugins-v2/plugins/garmin-hr/conf.xml 2009-10-12 07:34:20 UTC (rev 365) @@ -2,9 +2,9 @@ <pytrainer-plugin name="Garmin Heart Rate" description="Import yor records direclty from your garmin gps device with heart rate support" - plugincode="garmin-hr" + plugincode="garminhr" pluginbutton="Import from Garmin (HR support)" - executable="main.py" + executable="garminhr" > <conf-values variable="device" value="usb:"/> </pytrainer-plugin> Added: pytrainer/branches/plugins-v2/plugins/garmin-hr/garminhr.py =================================================================== --- pytrainer/branches/plugins-v2/plugins/garmin-hr/garminhr.py (rev 0) +++ pytrainer/branches/plugins-v2/plugins/garmin-hr/garminhr.py 2009-10-12 07:34:20 UTC (rev 365) @@ -0,0 +1,133 @@ +#!/usr/bin/python +# -*- coding: iso-8859-1 -*- + +#Copyright (C) Fiz Vazquez vu...@si... + +#This program is free software; you can redistribute it and/or +#modify it under the terms of the GNU General Public License +#as published by the Free Software Foundation; either version 2 +#of the License, or (at your option) any later version. + +#This program is distributed in the hope that it will be useful, +#but WITHOUT ANY WARRANTY; without even the implied warranty of +#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +#GNU General Public License for more details. + +#You should have received a copy of the GNU General Public License +#along with this program; if not, write to the Free Software +#Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +import os, sys +import logging +from lxml import etree + +import commands + +class garminhr(): + """ Plugin to import from a Garmin device using gpsbabel + Checks each activity to see if any entries are in the database with the same start time + Creates GPX files for each activity not in the database + + Note: using lxml see http://codespeak.net/lxml + """ + def __init__(self, parent = None, validate=False): + self.parent = parent + self.tmpdir = self.parent.conf.getValue("tmpdir") + self.data_path = os.path.dirname(__file__) + self.validate = validate + self.input_dev = None + + def run(self): + logging.debug(">>") + importfiles = [] + if self.garminDeviceExists(): + try: + gpsbabelOutputFile = "%s/file.gtrnctr" % (self.tmpdir) + testInputFile = "/home/johnb/garmin/2009.07.26\ 143201.TCX" + #TODO Remove Zenity below + outgps = commands.getstatusoutput("gpsbabel -t -i garmin -f %s -o gtrnctr -F %s | zenity --progress --pulsate --text='Loading Data' auto-close" % (self.input_dev, gpsbabelOutputFile) ) + if outgps[0]==0: + if outgps[1] == "Found no Garmin USB devices.": # check localizations + print "GPSBabel found no Garmin USB devices" + pass + else: #gpsbabel worked - now process file... + if self.valid_input_file(gpsbabelOutputFile): + tracks = self.getTracks(gpsbabelOutputFile) + logging.debug("Found %d tracks in %s" % (len(tracks), gpsbabelOutputFile)) + for track in tracks: #can be multiple tracks + if self.shouldImport(track): + gpxfile = "%s/garminhrfile%d.gpx" % (self.tmpdir, len(importfiles)) + self.createGPXfile(gpxfile, track) + importfiles.append(gpxfile) + logging.debug("Importing %s of %s tracks" % (len(importfiles), len(tracks)) ) + else: + logging.info("File %s failed validation" % (gpsbabelOutputFile)) + except Exception: + #TODO Remove Zenity below + os.popen("zenity --error --text='Can not handle Garmin device\nCheck your configuration\nCurrent usb port is set to:\t %s'" %self.input_dev); + print sys.exc_info()[0] + else: #No garmin device found + #TODO Remove Zenity below + os.popen("zenity --error --text='Can not handle Garmin device\nCheck your configuration\nCurrent usb port is set to:\t %s'" %self.input_dev); + logging.debug("<<") + return importfiles + + + def garminDeviceExists(self): + try: + outmod = commands.getstatusoutput('/sbin/lsmod | grep garmin_gps') + if outmod[0]==256: #there is no garmin_gps module loaded + self.input_dev = "usb:" + return True + else: + return False + except: + return False + + def valid_input_file(self, filename): + """ Function to validate input file if requested""" + if not self.validate: #not asked to validate + logging.debug("Not validating %s" % (filename) ) + return True + else: #Validate TCXv1, note are validating against gpsbabels 'broken' result... + xslfile = os.path.realpath(self.parent.parent.data_path)+ "/schemas/GarminTrainingCenterDatabase_v1-gpsbabel.xsd" + from lib.xmlValidation import xmlValidator + validator = xmlValidator() + return validator.validateXSL(filename, xslfile) + + def getTracks(self, filename): + """ Function to return all the tracks in a Garmin Training Center v1 file + """ + tree = etree.ElementTree(file=filename) + root = tree.getroot() + tracks = root.findall(".//{http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v1}Track") + return tracks + + def shouldImport(self, track): + """ Function determines whether a track should be imported or not + Currently using time only + """ + timeElement = track.find(".//{http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v1}Time") + if timeElement is None: + #print (etree.tostring(track, pretty_print=True)) + logging.debug("Error no time found in track") + return False + else: + time = timeElement.text + #comparing date and start time (sport may have been changed in DB after import) + if self.parent.parent.ddbb.select("records","*","date_time_utc=\"%s\"" % (time)): + logging.debug("Not importing track for time %s" % (time)) + return False + else: + return True + + def createGPXfile(self, gpxfile, track): + """ Function to transform a Garmin Training Center v1 Track to a valid GPX+ file + """ + xslt_doc = etree.parse(self.data_path+"/translate.xsl") + transform = etree.XSLT(xslt_doc) + result_tree = transform(track) + result_tree.write(gpxfile) + + + Deleted: pytrainer/branches/plugins-v2/plugins/garmin-hr/gtrnctr2gpx.py =================================================================== --- pytrainer/branches/plugins-v2/plugins/garmin-hr/gtrnctr2gpx.py 2009-10-11 08:31:03 UTC (rev 364) +++ pytrainer/branches/plugins-v2/plugins/garmin-hr/gtrnctr2gpx.py 2009-10-12 07:34:20 UTC (rev 365) @@ -1,82 +0,0 @@ -#!/usr/bin/python -# -*- coding: iso-8859-1 -*- - -#Copyright (C) Fiz Vazquez vu...@si... - -#This program is free software; you can redistribute it and/or -#modify it under the terms of the GNU General Public License -#as published by the Free Software Foundation; either version 2 -#of the License, or (at your option) any later version. - -#This program is distributed in the hope that it will be useful, -#but WITHOUT ANY WARRANTY; without even the implied warranty of -#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -#GNU General Public License for more details. - -#You should have received a copy of the GNU General Public License -#along with this program; if not, write to the Free Software -#Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - -import sys - -import xml.dom.minidom - -#the _variables are the gpx ones. The variables are the xcsv one - - -def gtrnctr2gpx(gtrnctrfile,gpxfile): - dom = xml.dom.minidom.parse(gtrnctrfile) - d = xml.dom.minidom.getDOMImplementation() - _dom = d.createDocument(None,"gpx",None) - _gpx_element = _dom.documentElement - _gpx_element.setAttribute('creator',"pytrainer http://pytrainer.e-oss.net") - _gpx_element.setAttribute('version',"1.1") - _gpx_element.setAttribute('xmlns',"http://www.topografix.com/GPX/1/1") - _gpx_element.setAttribute('xmlns:geocache',"http://www.groundspeak.com/cache/1/0") - _gpx_element.setAttribute('xmlns:gpxdata',"http://www.cluetrust.com/XML/GPXDATA/1/0") - _gpx_element.setAttribute('xmlns:xsi',"http://www.w3.org/2001/XMLSchema-instance") - _gpx_element.setAttribute('xsi:schemaLocation',"http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd http://www.cluetrust.com/XML/GPXDATA/1/0 http://www.cluetrust.com/Schemas/gpxdata10.xsd") - - trks = dom.getElementsByTagName("Track") - nametrack = 0 - for trk in trks: - nametrack = nametrack+1 - _trk = _dom.createElement("trk") - _name = _dom.createElement("name") - _name.appendChild(_dom.createTextNode("%s"%str(nametrack))) - _trk.appendChild(_name) - trkpoints = trk.getElementsByTagName("Trackpoint") - for trkpoint in trkpoints: - _trkpt = _dom.createElement("trkpt") - time = trkpoint.getElementsByTagName("Time")[0].firstChild.data - alt = trkpoint.getElementsByTagName("AltitudeMeters")[0].firstChild.data - if len(trkpoint.getElementsByTagName("HeartRateBpm"))>0: - hr = trkpoint.getElementsByTagName("HeartRateBpm")[0].firstChild.data - else: - hr = "0" - lat = trkpoint.getElementsByTagName("LatitudeDegrees")[0].firstChild.data - lon = trkpoint.getElementsByTagName("LongitudeDegrees")[0].firstChild.data - - _time = _dom.createElement("time") - _ele = _dom.createElement("ele") - _hr = _dom.createElement("gpxdata:hr") - _extensions = _dom.createElement("extensions") - _time.appendChild(_dom.createTextNode(time)) - _ele.appendChild(_dom.createTextNode(alt)) - _hr.appendChild(_dom.createTextNode(hr)) - _extensions.appendChild(_hr) - _trkpt.appendChild(_time) - _trkpt.appendChild(_ele) - _trkpt.appendChild(_extensions) - _trkpt.setAttribute('lat', lat) - _trkpt.setAttribute('lon', lon) - _trk.appendChild(_trkpt) - _gpx_element.appendChild(_trk) - - f = open(gpxfile, 'w') - #_dom.writexml(f) - #f.write(_dom.toprettyxml()) - f.write(_dom.toxml()) - f.close() - Deleted: pytrainer/branches/plugins-v2/plugins/garmin-hr/main.py =================================================================== --- pytrainer/branches/plugins-v2/plugins/garmin-hr/main.py 2009-10-11 08:31:03 UTC (rev 364) +++ pytrainer/branches/plugins-v2/plugins/garmin-hr/main.py 2009-10-12 07:34:20 UTC (rev 365) @@ -1,63 +0,0 @@ -#!/usr/bin/python -# -*- coding: iso-8859-1 -*- - -#Copyright (C) Fiz Vazquez vu...@si... - -#This program is free software; you can redistribute it and/or -#modify it under the terms of the GNU General Public License -#as published by the Free Software Foundation; either version 2 -#of the License, or (at your option) any later version. - -#This program is distributed in the hope that it will be useful, -#but WITHOUT ANY WARRANTY; without even the implied warranty of -#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -#GNU General Public License for more details. - -#You should have received a copy of the GNU General Public License -#along with this program; if not, write to the Free Software -#Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - -from optparse import OptionParser -#from gtrnctr2gpx import gtrnctr2gpx -import os -import commands - -parser = OptionParser() -parser.add_option("-d", "--device", dest="device") -(options,args) = parser.parse_args() -gtrnctrFile="/tmp/file.gtrnctr" -gtrnctrFileMod="/tmp/file_mod.gtrnctr" -input_dev = options.device - -# ToDo (19.05.2008): better exception handling -try: - outmod = commands.getstatusoutput('/sbin/lsmod | grep garmin_gps') - #os.popen("zenity --error --text='Devuelve: %s'" %str(outmod)) - if outmod[0]==256: #there is no garmin_gps module loaded - input_dev = "usb:" - else: - raise Exception - # Can't export to GPX directly because lack of support for heartrate and sports (1.0 version, may change when gpsbabel supports 1.1 with custom fields) - outgps = commands.getstatusoutput("gpsbabel -t -i garmin -f %s -o gtrnctr -F /tmp/file.gtrnctr | zenity --progress --pulsate --text='Loading Data' auto-close" %input_dev) - #os.popen("zenity --error --text='Devuelve: %s'" %str(outgps)) - # XML file from gpsbabel refers to schemas and namespace definitions which are no longer available, removing this info - dgg - 12.05.2008 - if outgps[0]==0: - if outgps[1] == "Found no Garmin USB devices.": # check localizations - raise Exception - else: - if os.path.isfile(gtrnctrFile): - f = open(gtrnctrFile,"r") - lines = f.readlines() - f.close() - f = open(gtrnctrFileMod,'w') - headers = lines[0]+'<TrainingCenterDatabase>\n' - f.write(headers) - f.write(''.join(lines[6:])) - f.close() - print gtrnctrFileMod - else: - raise Exception -except Exception: - os.popen("zenity --error --text='Can not handle Garmin device\nCheck your configuration\nCurrent usb port is set to:\t %s'" %input_dev); - Added: pytrainer/branches/plugins-v2/plugins/garmin-hr/translate.xsl =================================================================== --- pytrainer/branches/plugins-v2/plugins/garmin-hr/translate.xsl (rev 0) +++ pytrainer/branches/plugins-v2/plugins/garmin-hr/translate.xsl 2009-10-12 07:34:20 UTC (rev 365) @@ -0,0 +1,58 @@ +<?xml version="1.0"?> + +<!-- note defining a namespace for TrainingCenterDatabase as the translation does not seem to work with a default namespace --> +<xsl:stylesheet version="1.0" +xmlns:t="http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v1" +xmlns:xsl="http://www.w3.org/1999/XSL/Transform" +> +<xsl:output method="xml" indent="yes" omit-xml-declaration="no"/> + +<!-- this is a bit of a messy way to get whitespace into the output - but it works --> +<xsl:variable name="newline"><xsl:text> +</xsl:text></xsl:variable> + +<xsl:template match="/"> + <gpx xmlns="http://www.topografix.com/GPX/1/1" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:gpxdata="http://www.cluetrust.com/XML/GPXDATA/1/0" + creator="pytrainer http://sourceforge.net/projects/pytrainer" version="1.1" + xsi:schemaLocation="http://www.topografix.com/GPX/1/1 + http://www.topografix.com/GPX/1/1/gpx.xsd + http://www.cluetrust.com/XML/GPXDATA/1/0 + http://www.cluetrust.com/Schemas/gpxdata10.xsd"> + + <xsl:value-of select="$newline"/> + <xsl:variable name="sport">"Run"</xsl:variable> + <xsl:variable name="time"><xsl:value-of select="t:Track/t:Trackpoint/t:Time"/></xsl:variable> + <xsl:variable name="name"><xsl:value-of select="$sport"/><xsl:value-of select="substring($time, 1,10)"/></xsl:variable> + <metadata><xsl:value-of select="$newline"/> + <name><xsl:value-of select="$name"/></name><xsl:value-of select="$newline"/> + <link href="http://sourceforge.net/projects/pytrainer"/><xsl:value-of select="$newline"/> + <time><xsl:value-of select="$time"/></time><xsl:value-of select="$newline"/> + </metadata><xsl:value-of select="$newline"/> + <trk><xsl:value-of select="$newline"/> + <xsl:for-each select="t:Track"> + <trkseg><xsl:value-of select="$newline"/> + <xsl:for-each select="t:Trackpoint"> + <!-- only output a trkpt if a position exists --> + <xsl:if test="t:Position"> + <xsl:variable name="lat"><xsl:value-of select="t:Position/t:LatitudeDegrees"/></xsl:variable> + <xsl:variable name="lon"><xsl:value-of select="t:Position/t:LongitudeDegrees"/></xsl:variable> + <trkpt lat="{$lat}" lon="{$lon}"><xsl:value-of select="$newline"/> + <ele><xsl:value-of select="t:AltitudeMeters"/></ele><xsl:value-of select="$newline"/> + <time><xsl:value-of select="t:Time"/></time><xsl:value-of select="$newline"/> + <xsl:if test="t:HeartRateBpm/t:Value"> + <extensions><xsl:value-of select="$newline"/> + <gpxdata:hr><xsl:value-of select="t:HeartRateBpm/t:Value"/></gpxdata:hr><xsl:value-of select="$newline"/> + </extensions><xsl:value-of select="$newline"/> + </xsl:if> + </trkpt><xsl:value-of select="$newline"/> + </xsl:if> + </xsl:for-each> + <xsl:value-of select="$newline"/> + </trkseg><xsl:value-of select="$newline"/> + </xsl:for-each> + </trk><xsl:value-of select="$newline"/> + </gpx><xsl:value-of select="$newline"/> +</xsl:template> +</xsl:stylesheet> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |