-
Notifications
You must be signed in to change notification settings - Fork 7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Export Workout Charts as TCX file format #29
Comments
Hi Joel,
Yes I think that you should be able to implement this using plugins. Practically all internals are available through the plugins. When you add an example plugin and open the source code in the online editor your can directly type in code. All the logs are stored in the log object. This object has an array named logs with all the logs.
When you type in the follow code you will see al the properties
pm3.log.logs
get the first log in the array
pm3.log.logs[0]
From here you can access a log and convert it into an pm3. The complete api is also downloadable as typescript definition format.
http://www.vangulik.org/Ergometer/typescripts/ErgometerApp.d.ts
ErgometerApp.d
Text Document · 182 KB
More info on writing plugins:
https://tijmenvangulik.github.io/Ergometerspace/PLUGINS.html
You may need to include a third party app. Ergometer space I also add extra javascript libraries on the fly using javascript. If you have trouble with this I can help you. This feature is also something which I would like to have in ergometer-space so it may also be a combined effort, for example if you could convert a log of ergometer-space to a garmin tcx file using typescript/javascript, I could write the UI around it so it will work in all online and offline apps.
Tijmen
… On 16 Feb 2024, at 05:25, joelbarrette ***@***.***> wrote:
I'm looking to get data such as power, stroke rate and heart rate converted to a TCX file format so it can be exported to other programs like Garmin connect.
It's doable manually by exporting the CSV data and re-organizing the data, the biggest hurdle being the individual timestamps need to be calculated using the offsets.
Is this something that I could implement using the plugins?
Thanks,
Joel
—
Reply to this email directly, view it on GitHub <#29>, or unsubscribe <https://github.com/notifications/unsubscribe-auth/AAVG7NRNZNXOOHXKM7VYALTYT3NTPAVCNFSM6AAAAABDLMULISVHI2DSMVQWIX3LMV43ASLTON2WKOZSGEZTOOBUG43DCNY>.
You are receiving this because you are subscribed to this thread.
|
Hi Tijmen, Thanks for your quick response! I'll use this as a starting point, I'd already started exploring some of the js objects so thank you for pointing me right to where the data I need is. I shouldn't have much trouble writing the code to generate the TCX format from the data. TCX is the simplest but only supports a few data streams so if I figure that out I may also look into .FIT which is more complicated but extensible. This would open up the option of including the split pace as a data stream. I think this will have significant utility, from what I've seen no other applications can do this for the older PM3 and PM4s (which is what I have) not even RowPro, they only provide a summary entry which is useless if you want to compare HR and Power graphs within efforts of a single activity which I do all the time. Joel |
Success with the development, feel free to ask questions.
Tijmen
… On 16 Feb 2024, at 20:34, joelbarrette ***@***.***> wrote:
Hi Tijmen,
Thanks for your quick response! I'll use this as a starting point, I'd already started exploring some of the js objects so thank you for pointing me right to where the data I need is.
I shouldn't have much trouble writing the code to generate the TCX format from the data. TCX is the simplest but only supports a few data streams so if I figure that out I may also look into .FIT which is more complicated but extensible. This would open up the option of including the split pace as a data stream.
I think this will have significant utility, from what I've seen no other applications can do this for the older PM3 and PM4s (which is what I have) not even RowPro, they only provide a summary entry which is useless if you want to compare HR and Power graphs within efforts of a single activity which I do all the time.
Joel
—
Reply to this email directly, view it on GitHub <#29 (comment)>, or unsubscribe <https://github.com/notifications/unsubscribe-auth/AAVG7NUVR5KAE6FUNQGP6ATYT6YFXAVCNFSM6AAAAABDLMULISVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTSNBZGIYDMNZVGE>.
You are receiving this because you commented.
|
Hi Tijmen, I was successful in building a working TCX file content but I've run into a few bumps. First thing is for some reason, the timestamp I'm trying to use here: I'm also wondering if there's a way for me to get the map location as well, if I had lat/long per stroke that could be included as well which would allow for speed splits. I could also just hardcode it at random location and just increment either the lat/long by converting the value of Let me know what you think, also unfortunately all the spaces/indetations in the strings are necessary, Garmin connect can handle TCX without indents but Strava is more picky.
|
Hi
I am not yet sure what goes wrong in your code because timeStampDate is the date / time of the training . It is a Date object
timeStampDate. I also use this value in my code at it works without problem. In your example code timeStampDate is not used so I cannot check what is wrong.
I have created an example how you can replace the csv export with a different export. This will make testing easier
module tijmenvangulik_examples_valuewidgets { //make a name space to prevent mix ups
class ExamplePlugin extends ExternalPlugin {
private _oldExport : any;
public exportCSV(exportItem : pm3.WorkoutLogItem) : string {
alert("test");
var data= `<xml>
<value>${exportItem.timeStampDate.toISOString()}</value>
</xml>
`
return "My export"
}
public init() {
this._oldExport=pm3.log.exportCSV;
pm3.log.exportCSV=this.exportCSV.bind(this)
}
public remove() {
pm3.log.exportCSV=this._oldExport;
}
}
var plugin : ExamplePlugin;
plugin = new ExamplePlugin();
}
This is how the csv export looks like:
public exportCSV(exportItem : pm3.WorkoutLogItem) : string {
let exportData=[];
this.logs.forEach((log)=>{
if ((exportItem==null && log.isSelected) || log ==exportItem) {
var heartRateZones=(Array.isArray(log.heartRateZones) && log.heartRateZones.length==5)?log.heartRateZones:[0,0,0,0,0];
var data={
training: pm3.getTrainingDataCaption(log),
timeStamp: log.timeStampDate,
duration: utilities.formatRelativeTime(new Date(log.endDuration)),
distance: log.endDistance,
drag:log.lastStroke.dragFactor,
split: utilities.formatRelativeTime( pm3.calcTrainingDataSplitTime(log) ),
description: log.description,
heartrate_zone1:utilities.formatRelativeTime(new Date(heartRateZones[4])),
heartrate_zone2:utilities.formatRelativeTime(new Date(heartRateZones[3])),
heartrate_zone3:utilities.formatRelativeTime(new Date(heartRateZones[2])),
heartrate_zone4:utilities.formatRelativeTime(new Date(heartRateZones[1])),
heartrate_zone5:utilities.formatRelativeTime(new Date(heartRateZones[0])),
totalCalories: log.totalCalories??0,
power:log.averagePower??0,
strokeCount:log.lastStroke?.strokeCount??0
}
exportData.push(data);
}
});
return utilities.convertArrayOfObjectsToCSV({data: exportData});
}
The map widget may be used to calculate coordinates . It has a track (_track) with coordinates and distances. The map widgets uses calcNextCoordinate to calculate the positon. However I have not yet made an easy public function for this which converts a distance into a coordinate.
ergometerWidgets.mapWidget
Also a tip. You can use the new strings in typescrip. this will make your code easier to ready:
var data= `<xml>
<value>${exportItem.timeStampDate.toISOString()}</value>
</xml>
`
… On 17 Feb 2024, at 00:16, joelbarrette ***@***.***> wrote:
Hi Tijmen,
I was successful in building a working TCX file content but I've run into a few bumps.
First thing is for some reason, the timestamp I'm trying to use here: pm3.log.logs[0].timeStampDate seem to just be the current date. To generate the TCX properly I'll need the actual date of the activity. So in the meantime I'm just setting the date manually.
I'm also wondering if there's a way for me to get the map location as well, if I had lat/long per stroke that could be included as well which would allow for speed splits. I could also just hardcode it at random location and just increment either the lat/long by converting the value of pm3.log.logs,stroke,distance to degrees and using that.
Let me know what you think, also unfortunately all the spaces/indetations in the strings are necessary, Garmin connect can handle TCX without indents but Strava is more picky.
var logs = pm3.log.logs;
var testlog = logs[0]
var startDate = new Date('February 16, 2024 2:49:00')
var TCX = "";
// appending the start of the XML
TCX += "\<?xml version=\"1.0\" encoding=\"UTF-8\"?\>\n\<TrainingCenterDatabase\n xsi:schemaLocation=\"http:\/\/www.garmin.com\/xmlschemas\/TrainingCenterDatabase\/v2 http:\/\/www.garmin.com\/xmlschemas\/TrainingCenterDatabasev2.xsd\"\n xmlns:ns5=\"http:\/\/www.garmin.com\/xmlschemas\/ActivityGoals\/v1\"\n xmlns:ns3=\"http:\/\/www.garmin.com\/xmlschemas\/ActivityExtension\/v2\"\n xmlns:ns2=\"http:\/\/www.garmin.com\/xmlschemas\/UserProfile\/v2\"\n xmlns=\"http:\/\/www.garmin.com\/xmlschemas\/TrainingCenterDatabase\/v2\"\n xmlns:xsi=\"http:\/\/www.w3.org\/2001\/XMLSchema-instance\" xmlns:ns4=\"http:\/\/www.garmin.com\/xmlschemas\/ProfileExtension\/v1\"\>\n\ <Activities\>\n\ <Activity Sport=\"Other\"\>\n"
// adding date as ID
TCX += " \<Id\>" + startDate.toISOString() + "\<\/Id\>\n"
// adding lap time
TCX += " \<Lap StartTime=\"" + startDate.toISOString() + "\"\>\n"
// adding duration
TCX += " \<TotalTimeSeconds\>" + testlog.endDuration/1000 + "\<\/TotalTimeSeconds\>\n"
// adding other parts
TCX += " \<TriggerMethod\>Manual\<\/TriggerMethod\>\n"
TCX += " \<Track\>\n"
//iterate accross strokes
for(let stroke = 0; stroke < testlog.strokes.length; stroke += 2){
TCX += " \<Trackpoint\>\n"
// adding timestamp, this is where I'm just hardcoding it the same as above
var timestamp = new Date('February 16, 2024 2:49:00')
timestamp.setSeconds(startDate.getSeconds() + testlog.strokes[stroke].workTime.getSeconds() + (testlog.strokes[stroke].workTime.getMinutes()*60))
TCX += " \<Time\>" + timestamp.toISOString() + "\<\/Time\>\n"
// adding HR
TCX += " \<HeartRateBpm\>\n \<Value\>" + testlog.strokes[stroke].heartRate + "\<\/Value\>\n \<\/HeartRateBpm\>\n"
// adding Stroke Rate
TCX += " \<Cadence\>" + testlog.strokes[stroke].strokesPerMinute + "\<\/Cadence\>\n"
// adding power
TCX += " \<Extensions\>\n \<ns3:TPX\>\n \<ns3:Watts\>"+ testlog.strokes[stroke].power.toString() +"\<\/ns3:Watts\>\n \<\/ns3:TPX\>\n \<\/Extensions\>\n"
// close trackpoint tag
TCX += " \<\/Trackpoint\>\n"
}
TCX += " \<\/Track\>\n \<\/Lap\>\n"
TCX += " \<Creator xsi:type=\"Device_t\"\>\n \<Name\>--No GPS SELECTED--\<\/Name\>\n \<UnitId\>0\<\/UnitId\>\n \<ProductID\>0\<\/ProductID\>\n \<Version\>\n \<VersionMajor\>0\<\/VersionMajor\>\n \<VersionMinor\>0\<\/VersionMinor\>\n \<BuildMajor\>1\<\/BuildMajor\>\n \<BuildMinor\>1\<\/BuildMinor\>\n \<\/Version\>\n \<\/Creator\>\n \<\/Activity\>\n \<\/Activities\>\n \<Author xsi:type=\"Application_t\"\>\n \<Name\>GOTOES STRAVA TOOLS\<\/Name\>\n \<Build\>\n \<Version\>\n \<VersionMajor\>23\<\/VersionMajor\>\n \<VersionMinor\>9\<\/VersionMinor\>\n \<BuildMajor\>1\<\/BuildMajor\>\n \<BuildMinor\>1\<\/BuildMinor\>\n \<\/Version\>\n \<\/Build\>\n \<LangID\>en\<\/LangID\>\n \<PartNumber\>1\<\/PartNumber\>\n \<\/Author\>\n\<\/TrainingCenterDatabase\>"
console.log(TCX)
—
Reply to this email directly, view it on GitHub <#29 (comment)>, or unsubscribe <https://github.com/notifications/unsubscribe-auth/AAVG7NRAC4S3IRDLJAFVTHDYT7SEPAVCNFSM6AAAAABDLMULISVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTSNBZGQ3DSMZXHE>.
You are receiving this because you commented.
|
Hi,
In the next version I will make my map widget position calculation public :
public distanceToMapPosition(distance : number) : MapCoordinate {
… On 16 Feb 2024, at 20:34, joelbarrette ***@***.***> wrote:
Hi Tijmen,
Thanks for your quick response! I'll use this as a starting point, I'd already started exploring some of the js objects so thank you for pointing me right to where the data I need is.
I shouldn't have much trouble writing the code to generate the TCX format from the data. TCX is the simplest but only supports a few data streams so if I figure that out I may also look into .FIT which is more complicated but extensible. This would open up the option of including the split pace as a data stream.
I think this will have significant utility, from what I've seen no other applications can do this for the older PM3 and PM4s (which is what I have) not even RowPro, they only provide a summary entry which is useless if you want to compare HR and Power graphs within efforts of a single activity which I do all the time.
Joel
—
Reply to this email directly, view it on GitHub <#29 (comment)>, or unsubscribe <https://github.com/notifications/unsubscribe-auth/AAVG7NUVR5KAE6FUNQGP6ATYT6YFXAVCNFSM6AAAAABDLMULISVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTSNBZGIYDMNZVGE>.
You are receiving this because you commented.
|
I have published 5.4.0 with the distanceToMapPosition feature. |
Hi Tijmen, Thanks again for you work getting me up and running. I really appreciate the part about Typescript strings, I'd figured there was something like that but I haven't coded in JS/TS in a while. module tijmenvangulik_examples_valuewidgets { //make a name space to prevent mix ups
class ExamplePlugin extends ExternalPlugin {
private _oldExport : any;
public exportCSV(exportItem : pm3.WorkoutLogItem) : string {
//Forming first part of the TCX file
var TCXcontent = `<?xml version="1.0" encoding="UTF-8"?><TrainingCenterDatabase
xsi:schemaLocation="http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2 http://www.garmin.com/xmlschemas/TrainingCenterDatabasev2.xsd"
xmlns:ns5="http://www.garmin.com/xmlschemas/ActivityGoals/v1"
xmlns:ns3="http://www.garmin.com/xmlschemas/ActivityExtension/v2"
xmlns:ns2="http://www.garmin.com/xmlschemas/UserProfile/v2"
xmlns="http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ns4="http://www.garmin.com/xmlschemas/ProfileExtension/v1">
<Activities>
<Activity Sport="Other">
<Id>${exportItem.timeStampDate.toISOString()}</Id>
<Lap StartTime="${exportItem.timeStampDate.toISOString()}">
<TotalTimeSeconds>${exportItem.endDuration/1000}</TotalTimeSeconds>
<DistanceMeters>${exportItem.distance}</DistanceMeters>
<TriggerMethod>Distance</TriggerMethod>
<Track\>
`
//Creating TCX trackpoints via iterating across log.strokes
var startDate = new Date(exportItem.timeStampDate.toISOString())
for(let stroke = 1; stroke < exportItem.strokes.length-1; stroke += 2){
var timestamp = new Date(exportItem.timeStampDate.toISOString())
timestamp.setSeconds(startDate.getSeconds() + (exportItem.strokes[stroke].workTime.getMilliseconds() + exportItem.strokes[stroke].workTime.getSeconds()*1000 + (exportItem.strokes[stroke].workTime.getMinutes()*60000))/1000)
TCXcontent += ` <Trackpoint>
<Time>${timestamp.toISOString()}</Time>
<Position>
<LatitudeDegrees>${ergometerWidgets.mapWidget.distanceToMapPosition(exportItem.strokes[stroke].distance).latitude}</LatitudeDegrees>
<LongitudeDegrees>${ergometerWidgets.mapWidget.distanceToMapPosition(exportItem.strokes[stroke].distance).longitude}</LongitudeDegrees>
</Position>
<DistanceMeters>${exportItem.strokes[stroke].distance}</DistanceMeters>
<HeartRateBpm>
<Value>${exportItem.strokes[stroke].heartRate}</Value>
</HeartRateBpm>
<Cadence>${exportItem.strokes[stroke].strokesPerMinute}</Cadence>
<Extensions>
<ns3:TPX>
<ns3:Watts>${exportItem.strokes[stroke].power.toString()}</ns3:Watts>
</ns3:TPX>
</Extensions>
</Trackpoint>
`
}
// adding TCX ending content
TCXcontent += ` </Track>
</Lap>
<Creator xsi:type="Device_t">
<Name>--No GPS SELECTED--</Name>
<UnitId>0</UnitId>
<ProductID>0</ProductID>
<Version>
<VersionMajor>0</VersionMajor>
<VersionMinor>0</VersionMinor>
<BuildMajor>1</BuildMajor>
<BuildMinor>1</BuildMinor>
</Version>
</Creator>
</Activity>
</Activities>
<Author xsi:type="Application_t">
<Name>GOTOES STRAVA TOOLS</Name>
<Build>
<Version>
<VersionMajor>23</VersionMajor>
<VersionMinor>9</VersionMinor>
<BuildMajor>1</BuildMajor>
<BuildMinor>1</BuildMinor>
</Version>
</Build>
<LangID>en</LangID>
<PartNumber>1</PartNumber>
</Author>
</TrainingCenterDatabase>`
return TCXcontent
}
public init() {
this._oldExport=pm3.log.exportCSV;
pm3.log.exportCSV=this.exportCSV.bind(this);
}
public remove() {
pm3.log.exportCSV=this._oldExport;
}
}
var plugin : ExamplePlugin;
plugin = new ExamplePlugin();
} This now works almost as expected, the only thing is the exported file is a .CSV and it also includes the CSV export at the end of the file. The other thing that I found was when iterating across log.logs.strokes is that there seems to be duplicate entries, ie, every second stroke has the same power, hr, timestamp etc. (I'm assuming this is for Power/rest halves of the stroke) To get around this I was iterating my for loop ++2 but after I added the Lat/long part I found that the final stroke has a distance of "0" which causes the lat/long lookup to fail. Is there a better way I could be doing this? Thanks, |
Hi Joel,
Good to see you are making progress. I will add this week a feature so that you can add your own export with your own title and file extension. That will fix the file extension problem and give you a more pemenant solution (the current way was a bit of a temporary hack). When your code is fully working I hope I could integrate your code into the source code or that it will be available in the plugin list. Please send me the log which have the duplicated values and I will check it out (you can choose export from the log (please do not choose csv).
Tijmen
… On 19 Feb 2024, at 03:15, joelbarrette ***@***.***> wrote:
Hi Tijmen,
Thanks again for you work getting me up and running. I really appreciate the part about Typescript strings, I'd figured there was something like that but I haven't coded in JS/TS in a while.
module tijmenvangulik_examples_valuewidgets { //make a name space to prevent mix ups
class ExamplePlugin extends ExternalPlugin {
private _oldExport : any;
public exportCSV(exportItem : pm3.WorkoutLogItem) : string {
//Forming first part of the TCX file
var TCXcontent = `<?xml version="1.0" encoding="UTF-8"?><TrainingCenterDatabase
xsi:schemaLocation="http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2 http://www.garmin.com/xmlschemas/TrainingCenterDatabasev2.xsd"
xmlns:ns5="http://www.garmin.com/xmlschemas/ActivityGoals/v1"
xmlns:ns3="http://www.garmin.com/xmlschemas/ActivityExtension/v2"
xmlns:ns2="http://www.garmin.com/xmlschemas/UserProfile/v2"
xmlns="http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ns4="http://www.garmin.com/xmlschemas/ProfileExtension/v1">
<Activities>
<Activity Sport="Other">
<Id>${exportItem.timeStampDate.toISOString()}</Id>
<Lap StartTime="${exportItem.timeStampDate.toISOString()}">
<TotalTimeSeconds>${exportItem.endDuration/1000}</TotalTimeSeconds>
<DistanceMeters>${exportItem.distance}</DistanceMeters>
<TriggerMethod>Distance</TriggerMethod>
<Track\>
`
//Creating TCX trackpoints via iterating across log.strokes
var startDate = new Date(exportItem.timeStampDate.toISOString())
for(let stroke = 1; stroke < exportItem.strokes.length-1; stroke += 2){
var timestamp = new Date(exportItem.timeStampDate.toISOString())
timestamp.setSeconds(startDate.getSeconds() + (exportItem.strokes[stroke].workTime.getMilliseconds() + exportItem.strokes[stroke].workTime.getSeconds()*1000 + (exportItem.strokes[stroke].workTime.getMinutes()*60000))/1000)
TCXcontent += ` <Trackpoint>
<Time>${timestamp.toISOString()}</Time>
<Position>
<LatitudeDegrees>${ergometerWidgets.mapWidget.distanceToMapPosition(exportItem.strokes[stroke].distance).latitude}</LatitudeDegrees>
<LongitudeDegrees>${ergometerWidgets.mapWidget.distanceToMapPosition(exportItem.strokes[stroke].distance).longitude}</LongitudeDegrees>
</Position>
<DistanceMeters>${exportItem.strokes[stroke].distance}</DistanceMeters>
<HeartRateBpm>
<Value>${exportItem.strokes[stroke].heartRate}</Value>
</HeartRateBpm>
<Cadence>${exportItem.strokes[stroke].strokesPerMinute}</Cadence>
<Extensions>
<ns3:TPX>
<ns3:Watts>${exportItem.strokes[stroke].power.toString()}</ns3:Watts>
</ns3:TPX>
</Extensions>
</Trackpoint>
`
}
// adding TCX ending content
TCXcontent += ` </Track>
</Lap>
<Creator xsi:type="Device_t">
<Name>--No GPS SELECTED--</Name>
<UnitId>0</UnitId>
<ProductID>0</ProductID>
<Version>
<VersionMajor>0</VersionMajor>
<VersionMinor>0</VersionMinor>
<BuildMajor>1</BuildMajor>
<BuildMinor>1</BuildMinor>
</Version>
</Creator>
</Activity>
</Activities>
<Author xsi:type="Application_t">
<Name>GOTOES STRAVA TOOLS</Name>
<Build>
<Version>
<VersionMajor>23</VersionMajor>
<VersionMinor>9</VersionMinor>
<BuildMajor>1</BuildMajor>
<BuildMinor>1</BuildMinor>
</Version>
</Build>
<LangID>en</LangID>
<PartNumber>1</PartNumber>
</Author>
</TrainingCenterDatabase>`
return TCXcontent
}
public init() {
this._oldExport=pm3.log.exportCSV;
pm3.log.exportCSV=this.exportCSV.bind(this);
}
public remove() {
pm3.log.exportCSV=this._oldExport;
}
}
var plugin : ExamplePlugin;
plugin = new ExamplePlugin();
}
This now works almost as expected, the only thing is the exported file is a .CSV and it also includes the CSV export at the end of the file.
The other thing that I found was when iterating across log.logs.strokes is that there seems to be duplicate entries, ie, every second stroke has the same power, hr, timestamp etc. (I'm assuming this is for Power/rest halves of the stroke) To get around this I was iterating my for loop ++2 but after I added the Lat/long part I found that the final stroke has a distance of "0" which causes the lat/long lookup to fail. Is there a better way I could be doing this?
Thanks,
Joel
—
Reply to this email directly, view it on GitHub <#29 (comment)>, or unsubscribe <https://github.com/notifications/unsubscribe-auth/AAVG7NTG4D4X6I3TFRAASQTYUKYU7AVCNFSM6AAAAABDLMULISVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTSNJRGU3TQNBUGM>.
You are receiving this because you commented.
|
The new way of writing an export plugin. You will have to pass on a title, filename , mimetype and your export function
module tijmenvangulik_examples_export_demo { //make a name space to prevent mix ups
class ExamplePlugin extends ExternalPlugin {
private _oldExport : any;
public doExport(exportItem : pm3.WorkoutLogItem) : string {
var data= `<xml>
<value>${exportItem.timeStampDate.toISOString()}</value>
</xml>
`
return data;
}
public init() {
pm3.log.registerCustomExport(this,"Demo export","demo.xml","application/xml",this.doExport.bind(this));
}
public remove() {
pm3.log.deRegisterCustomExport(this.doExport);
}
}
var plugin : ExamplePlugin;
plugin = new ExamplePlugin();
}
It will show up in the workout chart

… On 19 Feb 2024, at 03:15, joelbarrette ***@***.***> wrote:
Hi Tijmen,
Thanks again for you work getting me up and running. I really appreciate the part about Typescript strings, I'd figured there was something like that but I haven't coded in JS/TS in a while.
module tijmenvangulik_examples_valuewidgets { //make a name space to prevent mix ups
class ExamplePlugin extends ExternalPlugin {
private _oldExport : any;
public exportCSV(exportItem : pm3.WorkoutLogItem) : string {
//Forming first part of the TCX file
var TCXcontent = `<?xml version="1.0" encoding="UTF-8"?><TrainingCenterDatabase
xsi:schemaLocation="http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2 http://www.garmin.com/xmlschemas/TrainingCenterDatabasev2.xsd"
xmlns:ns5="http://www.garmin.com/xmlschemas/ActivityGoals/v1"
xmlns:ns3="http://www.garmin.com/xmlschemas/ActivityExtension/v2"
xmlns:ns2="http://www.garmin.com/xmlschemas/UserProfile/v2"
xmlns="http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ns4="http://www.garmin.com/xmlschemas/ProfileExtension/v1">
<Activities>
<Activity Sport="Other">
<Id>${exportItem.timeStampDate.toISOString()}</Id>
<Lap StartTime="${exportItem.timeStampDate.toISOString()}">
<TotalTimeSeconds>${exportItem.endDuration/1000}</TotalTimeSeconds>
<DistanceMeters>${exportItem.distance}</DistanceMeters>
<TriggerMethod>Distance</TriggerMethod>
<Track\>
`
//Creating TCX trackpoints via iterating across log.strokes
var startDate = new Date(exportItem.timeStampDate.toISOString())
for(let stroke = 1; stroke < exportItem.strokes.length-1; stroke += 2){
var timestamp = new Date(exportItem.timeStampDate.toISOString())
timestamp.setSeconds(startDate.getSeconds() + (exportItem.strokes[stroke].workTime.getMilliseconds() + exportItem.strokes[stroke].workTime.getSeconds()*1000 + (exportItem.strokes[stroke].workTime.getMinutes()*60000))/1000)
TCXcontent += ` <Trackpoint>
<Time>${timestamp.toISOString()}</Time>
<Position>
<LatitudeDegrees>${ergometerWidgets.mapWidget.distanceToMapPosition(exportItem.strokes[stroke].distance).latitude}</LatitudeDegrees>
<LongitudeDegrees>${ergometerWidgets.mapWidget.distanceToMapPosition(exportItem.strokes[stroke].distance).longitude}</LongitudeDegrees>
</Position>
<DistanceMeters>${exportItem.strokes[stroke].distance}</DistanceMeters>
<HeartRateBpm>
<Value>${exportItem.strokes[stroke].heartRate}</Value>
</HeartRateBpm>
<Cadence>${exportItem.strokes[stroke].strokesPerMinute}</Cadence>
<Extensions>
<ns3:TPX>
<ns3:Watts>${exportItem.strokes[stroke].power.toString()}</ns3:Watts>
</ns3:TPX>
</Extensions>
</Trackpoint>
`
}
// adding TCX ending content
TCXcontent += ` </Track>
</Lap>
<Creator xsi:type="Device_t">
<Name>--No GPS SELECTED--</Name>
<UnitId>0</UnitId>
<ProductID>0</ProductID>
<Version>
<VersionMajor>0</VersionMajor>
<VersionMinor>0</VersionMinor>
<BuildMajor>1</BuildMajor>
<BuildMinor>1</BuildMinor>
</Version>
</Creator>
</Activity>
</Activities>
<Author xsi:type="Application_t">
<Name>GOTOES STRAVA TOOLS</Name>
<Build>
<Version>
<VersionMajor>23</VersionMajor>
<VersionMinor>9</VersionMinor>
<BuildMajor>1</BuildMajor>
<BuildMinor>1</BuildMinor>
</Version>
</Build>
<LangID>en</LangID>
<PartNumber>1</PartNumber>
</Author>
</TrainingCenterDatabase>`
return TCXcontent
}
public init() {
this._oldExport=pm3.log.exportCSV;
pm3.log.exportCSV=this.exportCSV.bind(this);
}
public remove() {
pm3.log.exportCSV=this._oldExport;
}
}
var plugin : ExamplePlugin;
plugin = new ExamplePlugin();
}
This now works almost as expected, the only thing is the exported file is a .CSV and it also includes the CSV export at the end of the file.
The other thing that I found was when iterating across log.logs.strokes is that there seems to be duplicate entries, ie, every second stroke has the same power, hr, timestamp etc. (I'm assuming this is for Power/rest halves of the stroke) To get around this I was iterating my for loop ++2 but after I added the Lat/long part I found that the final stroke has a distance of "0" which causes the lat/long lookup to fail. Is there a better way I could be doing this?
Thanks,
Joel
—
Reply to this email directly, view it on GitHub <#29 (comment)>, or unsubscribe <https://github.com/notifications/unsubscribe-auth/AAVG7NTG4D4X6I3TFRAASQTYUKYU7AVCNFSM6AAAAABDLMULISVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTSNJRGU3TQNBUGM>.
You are receiving this because you commented.
|
Hi Tijmen, Thanks for the update, I'll copy my code into that new plugin template. Here's a file that shows the duplicate strokes I was referring to. It's a 1k Erg I did yesterday on my C2 PM4: What I see is that after the first stroke, every second stroke has duplicate data, ie. stroke 2 & 3, I'm assuming that's because item 2 is the power phase and item 3 is the recovery phase. Since I don't need that extra data currently I'm just iterating across every power entry and then ignoring the last one since it has a distance of 0 for some reason. It works fine pretty much other than the total distance is off by one stroke. I could also add a case at the end that takes the total distance for the last stroke just so that it looks nicer. Up to you. Item 2 & 3 {
"splitTime": "1970-01-01T00:01:43.000Z",
"power": 322,
"strokesPerMinute": 34,
"workTime": "1970-01-01T00:00:02.710Z",
"distance": 12,
"heartRate": 98,
"recoveryRatio": 0,
"strokeCount": 2,
"strokeDistance": 0,
"forceCurve": [
85,
30,
58,
14,
47,
52,
0,
0
]
},
{
"splitTime": "1970-01-01T00:01:43.000Z",
"power": 322,
"strokesPerMinute": 34,
"workTime": "1970-01-01T00:00:02.710Z",
"distance": 12,
"heartRate": 98,
"recoveryRatio": 71.28666666666666,
"strokeCount": 2,
"strokeDistance": 0
}, Last item in the strokes array: {
"splitTime": "1970-01-01T00:01:52.000Z",
"power": 250,
"strokesPerMinute": 27,
"workTime": "1970-01-01T00:03:29.430Z",
"distance": 0,
"heartRate": 163,
"recoveryRatio": 72.045,
"strokeCount": 95,
"strokeDistance": 0
} |
Scratch what I said about the distance problems, I was able to fix it by changing how my for loop iterates. Here's the final code so far, I had to change the file type to TCX but other than that it's looking good: module joel_export_TCX { //make a name space to prevent mix ups
class ExamplePlugin extends ExternalPlugin {
private _oldExport : any;
public doExport(exportItem : pm3.WorkoutLogItem) : string {
//Forming first part of the TCX file
var TCXcontent = `<?xml version="1.0" encoding="UTF-8"?><TrainingCenterDatabase
xsi:schemaLocation="http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2 http://www.garmin.com/xmlschemas/TrainingCenterDatabasev2.xsd"
xmlns:ns5="http://www.garmin.com/xmlschemas/ActivityGoals/v1"
xmlns:ns3="http://www.garmin.com/xmlschemas/ActivityExtension/v2"
xmlns:ns2="http://www.garmin.com/xmlschemas/UserProfile/v2"
xmlns="http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ns4="http://www.garmin.com/xmlschemas/ProfileExtension/v1">
<Activities>
<Activity Sport="Other">
<Id>${exportItem.timeStampDate.toISOString()}</Id>
<Lap StartTime="${exportItem.timeStampDate.toISOString()}">
<TotalTimeSeconds>${exportItem.endDuration/1000}</TotalTimeSeconds>
<DistanceMeters>${exportItem.distance}</DistanceMeters>
<TriggerMethod>Distance</TriggerMethod>
<Track\>
`
//Creating TCX trackpoints via iterating across log.strokes
var startDate = new Date(exportItem.timeStampDate.toISOString())
for(let stroke = 0; stroke < exportItem.strokes.length-1; stroke += 2){
var timestamp = new Date(exportItem.timeStampDate.toISOString())
timestamp.setSeconds(startDate.getSeconds() + (exportItem.strokes[stroke].workTime.getMilliseconds() + exportItem.strokes[stroke].workTime.getSeconds()*1000 + (exportItem.strokes[stroke].workTime.getMinutes()*60000))/1000)
TCXcontent += ` <Trackpoint>
<Time>${timestamp.toISOString()}</Time>
<Position>
<LatitudeDegrees>${ergometerWidgets.mapWidget.distanceToMapPosition(exportItem.strokes[stroke].distance).latitude}</LatitudeDegrees>
<LongitudeDegrees>${ergometerWidgets.mapWidget.distanceToMapPosition(exportItem.strokes[stroke].distance).longitude}</LongitudeDegrees>
</Position>
<DistanceMeters>${exportItem.strokes[stroke].distance}</DistanceMeters>
<HeartRateBpm>
<Value>${exportItem.strokes[stroke].heartRate}</Value>
</HeartRateBpm>
<Cadence>${exportItem.strokes[stroke].strokesPerMinute}</Cadence>
<Extensions>
<ns3:TPX>
<ns3:Watts>${exportItem.strokes[stroke].power.toString()}</ns3:Watts>
</ns3:TPX>
</Extensions>
</Trackpoint>
`
}
// adding TCX ending content
TCXcontent += ` </Track>
</Lap>
<Creator xsi:type="Device_t">
<Name>--No GPS SELECTED--</Name>
<UnitId>0</UnitId>
<ProductID>0</ProductID>
<Version>
<VersionMajor>0</VersionMajor>
<VersionMinor>0</VersionMinor>
<BuildMajor>1</BuildMajor>
<BuildMinor>1</BuildMinor>
</Version>
</Creator>
</Activity>
</Activities>
<Author xsi:type="Application_t">
<Name>GOTOES STRAVA TOOLS</Name>
<Build>
<Version>
<VersionMajor>23</VersionMajor>
<VersionMinor>9</VersionMinor>
<BuildMajor>1</BuildMajor>
<BuildMinor>1</BuildMinor>
</Version>
</Build>
<LangID>en</LangID>
<PartNumber>1</PartNumber>
</Author>
</TrainingCenterDatabase>`
return TCXcontent
}
public init() {
pm3.log.registerCustomExport(this,"Demo export","demo.tcx","application/tcx",this.doExport.bind(this));
}
public remove() {
pm3.log.deRegisterCustomExport(this.doExport);
}
}
var plugin : ExamplePlugin;
plugin = new ExamplePlugin();
} |
Thank you for the info.
I have imported the workout log. The force curves look very strange to me. Even the correct curves have a lot of noice at the end. It almost looks that there may also be an hardware problem. I think I need some more info
* What kind of performance monitor PM5/PM3 or PM2?
* Do you use USB or Blue tooth. (in case of a PM5)
* What version/ software/hardware of the PM5. (you can make a phone of the version info screen, saves time)
* I assume you test on a PC or Mac, if other I would like to know.
Tijmen
P.S. All our communication is now online. You can also mail me on my private mail address : ***@***.***
P.S2 keep in mind that ergometerWidgets.mapWidget may be null when the end user does not use the map widget.
… On 19 Feb 2024, at 23:37, joelbarrette ***@***.***> wrote:
Scratch what I said about the distance problems, I was able to fix it by changing how my for loop iterates. Here's the final code so far, I had to change the file type to TCX but other than that it's looking good:
module joel_export_TCX { //make a name space to prevent mix ups
class ExamplePlugin extends ExternalPlugin {
private _oldExport : any;
public doExport(exportItem : pm3.WorkoutLogItem) : string {
//Forming first part of the TCX file
var TCXcontent = `<?xml version="1.0" encoding="UTF-8"?><TrainingCenterDatabase
xsi:schemaLocation="http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2 http://www.garmin.com/xmlschemas/TrainingCenterDatabasev2.xsd"
xmlns:ns5="http://www.garmin.com/xmlschemas/ActivityGoals/v1"
xmlns:ns3="http://www.garmin.com/xmlschemas/ActivityExtension/v2"
xmlns:ns2="http://www.garmin.com/xmlschemas/UserProfile/v2"
xmlns="http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ns4="http://www.garmin.com/xmlschemas/ProfileExtension/v1">
<Activities>
<Activity Sport="Other">
<Id>${exportItem.timeStampDate.toISOString()}</Id>
<Lap StartTime="${exportItem.timeStampDate.toISOString()}">
<TotalTimeSeconds>${exportItem.endDuration/1000}</TotalTimeSeconds>
<DistanceMeters>${exportItem.distance}</DistanceMeters>
<TriggerMethod>Distance</TriggerMethod>
<Track\>
`
//Creating TCX trackpoints via iterating across log.strokes
var startDate = new Date(exportItem.timeStampDate.toISOString())
for(let stroke = 0; stroke < exportItem.strokes.length-1; stroke += 2){
var timestamp = new Date(exportItem.timeStampDate.toISOString())
timestamp.setSeconds(startDate.getSeconds() + (exportItem.strokes[stroke].workTime.getMilliseconds() + exportItem.strokes[stroke].workTime.getSeconds()*1000 + (exportItem.strokes[stroke].workTime.getMinutes()*60000))/1000)
TCXcontent += ` <Trackpoint>
<Time>${timestamp.toISOString()}</Time>
<Position>
<LatitudeDegrees>${ergometerWidgets.mapWidget.distanceToMapPosition(exportItem.strokes[stroke].distance).latitude}</LatitudeDegrees>
<LongitudeDegrees>${ergometerWidgets.mapWidget.distanceToMapPosition(exportItem.strokes[stroke].distance).longitude}</LongitudeDegrees>
</Position>
<DistanceMeters>${exportItem.strokes[stroke].distance}</DistanceMeters>
<HeartRateBpm>
<Value>${exportItem.strokes[stroke].heartRate}</Value>
</HeartRateBpm>
<Cadence>${exportItem.strokes[stroke].strokesPerMinute}</Cadence>
<Extensions>
<ns3:TPX>
<ns3:Watts>${exportItem.strokes[stroke].power.toString()}</ns3:Watts>
</ns3:TPX>
</Extensions>
</Trackpoint>
`
}
// adding TCX ending content
TCXcontent += ` </Track>
</Lap>
<Creator xsi:type="Device_t">
<Name>--No GPS SELECTED--</Name>
<UnitId>0</UnitId>
<ProductID>0</ProductID>
<Version>
<VersionMajor>0</VersionMajor>
<VersionMinor>0</VersionMinor>
<BuildMajor>1</BuildMajor>
<BuildMinor>1</BuildMinor>
</Version>
</Creator>
</Activity>
</Activities>
<Author xsi:type="Application_t">
<Name>GOTOES STRAVA TOOLS</Name>
<Build>
<Version>
<VersionMajor>23</VersionMajor>
<VersionMinor>9</VersionMinor>
<BuildMajor>1</BuildMajor>
<BuildMinor>1</BuildMinor>
</Version>
</Build>
<LangID>en</LangID>
<PartNumber>1</PartNumber>
</Author>
</TrainingCenterDatabase>`
return TCXcontent
}
public init() {
pm3.log.registerCustomExport(this,"Demo export","demo.tcx","application/tcx",this.doExport.bind(this));
}
public remove() {
pm3.log.deRegisterCustomExport(this.doExport);
}
}
var plugin : ExamplePlugin;
plugin = new ExamplePlugin();
}
—
Reply to this email directly, view it on GitHub <#29 (comment)>, or unsubscribe <https://github.com/notifications/unsubscribe-auth/AAVG7NRHZZRN7AV2V7IXUELYUPH25AVCNFSM6AAAAABDLMULISVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTSNJTGIZTOMBTGQ>.
You are receiving this because you commented.
|
Also note it is better to take the endDistance instead of the distance. There can be a situation when you row 10 minutes and you have not set a distance. The endDistance is then correctly filled with the rowed distance.
… On 19 Feb 2024, at 23:37, joelbarrette ***@***.***> wrote:
Scratch what I said about the distance problems, I was able to fix it by changing how my for loop iterates. Here's the final code so far, I had to change the file type to TCX but other than that it's looking good:
module joel_export_TCX { //make a name space to prevent mix ups
class ExamplePlugin extends ExternalPlugin {
private _oldExport : any;
public doExport(exportItem : pm3.WorkoutLogItem) : string {
//Forming first part of the TCX file
var TCXcontent = `<?xml version="1.0" encoding="UTF-8"?><TrainingCenterDatabase
xsi:schemaLocation="http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2 http://www.garmin.com/xmlschemas/TrainingCenterDatabasev2.xsd"
xmlns:ns5="http://www.garmin.com/xmlschemas/ActivityGoals/v1"
xmlns:ns3="http://www.garmin.com/xmlschemas/ActivityExtension/v2"
xmlns:ns2="http://www.garmin.com/xmlschemas/UserProfile/v2"
xmlns="http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ns4="http://www.garmin.com/xmlschemas/ProfileExtension/v1">
<Activities>
<Activity Sport="Other">
<Id>${exportItem.timeStampDate.toISOString()}</Id>
<Lap StartTime="${exportItem.timeStampDate.toISOString()}">
<TotalTimeSeconds>${exportItem.endDuration/1000}</TotalTimeSeconds>
<DistanceMeters>${exportItem.distance}</DistanceMeters>
<TriggerMethod>Distance</TriggerMethod>
<Track\>
`
//Creating TCX trackpoints via iterating across log.strokes
var startDate = new Date(exportItem.timeStampDate.toISOString())
for(let stroke = 0; stroke < exportItem.strokes.length-1; stroke += 2){
var timestamp = new Date(exportItem.timeStampDate.toISOString())
timestamp.setSeconds(startDate.getSeconds() + (exportItem.strokes[stroke].workTime.getMilliseconds() + exportItem.strokes[stroke].workTime.getSeconds()*1000 + (exportItem.strokes[stroke].workTime.getMinutes()*60000))/1000)
TCXcontent += ` <Trackpoint>
<Time>${timestamp.toISOString()}</Time>
<Position>
<LatitudeDegrees>${ergometerWidgets.mapWidget.distanceToMapPosition(exportItem.strokes[stroke].distance).latitude}</LatitudeDegrees>
<LongitudeDegrees>${ergometerWidgets.mapWidget.distanceToMapPosition(exportItem.strokes[stroke].distance).longitude}</LongitudeDegrees>
</Position>
<DistanceMeters>${exportItem.strokes[stroke].distance}</DistanceMeters>
<HeartRateBpm>
<Value>${exportItem.strokes[stroke].heartRate}</Value>
</HeartRateBpm>
<Cadence>${exportItem.strokes[stroke].strokesPerMinute}</Cadence>
<Extensions>
<ns3:TPX>
<ns3:Watts>${exportItem.strokes[stroke].power.toString()}</ns3:Watts>
</ns3:TPX>
</Extensions>
</Trackpoint>
`
}
// adding TCX ending content
TCXcontent += ` </Track>
</Lap>
<Creator xsi:type="Device_t">
<Name>--No GPS SELECTED--</Name>
<UnitId>0</UnitId>
<ProductID>0</ProductID>
<Version>
<VersionMajor>0</VersionMajor>
<VersionMinor>0</VersionMinor>
<BuildMajor>1</BuildMajor>
<BuildMinor>1</BuildMinor>
</Version>
</Creator>
</Activity>
</Activities>
<Author xsi:type="Application_t">
<Name>GOTOES STRAVA TOOLS</Name>
<Build>
<Version>
<VersionMajor>23</VersionMajor>
<VersionMinor>9</VersionMinor>
<BuildMajor>1</BuildMajor>
<BuildMinor>1</BuildMinor>
</Version>
</Build>
<LangID>en</LangID>
<PartNumber>1</PartNumber>
</Author>
</TrainingCenterDatabase>`
return TCXcontent
}
public init() {
pm3.log.registerCustomExport(this,"Demo export","demo.tcx","application/tcx",this.doExport.bind(this));
}
public remove() {
pm3.log.deRegisterCustomExport(this.doExport);
}
}
var plugin : ExamplePlugin;
plugin = new ExamplePlugin();
}
—
Reply to this email directly, view it on GitHub <#29 (comment)>, or unsubscribe <https://github.com/notifications/unsubscribe-auth/AAVG7NRHZZRN7AV2V7IXUELYUPH25AVCNFSM6AAAAABDLMULISVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTSNJTGIZTOMBTGQ>.
You are receiving this because you commented.
|
I used your plugin to upload one of my workouts to garmin and it was accepted and really worked. Congratulations!
Tijmen
… On 19 Feb 2024, at 23:37, joelbarrette ***@***.***> wrote:
Scratch what I said about the distance problems, I was able to fix it by changing how my for loop iterates. Here's the final code so far, I had to change the file type to TCX but other than that it's looking good:
module joel_export_TCX { //make a name space to prevent mix ups
class ExamplePlugin extends ExternalPlugin {
private _oldExport : any;
public doExport(exportItem : pm3.WorkoutLogItem) : string {
//Forming first part of the TCX file
var TCXcontent = `<?xml version="1.0" encoding="UTF-8"?><TrainingCenterDatabase
xsi:schemaLocation="http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2 http://www.garmin.com/xmlschemas/TrainingCenterDatabasev2.xsd"
xmlns:ns5="http://www.garmin.com/xmlschemas/ActivityGoals/v1"
xmlns:ns3="http://www.garmin.com/xmlschemas/ActivityExtension/v2"
xmlns:ns2="http://www.garmin.com/xmlschemas/UserProfile/v2"
xmlns="http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ns4="http://www.garmin.com/xmlschemas/ProfileExtension/v1">
<Activities>
<Activity Sport="Other">
<Id>${exportItem.timeStampDate.toISOString()}</Id>
<Lap StartTime="${exportItem.timeStampDate.toISOString()}">
<TotalTimeSeconds>${exportItem.endDuration/1000}</TotalTimeSeconds>
<DistanceMeters>${exportItem.distance}</DistanceMeters>
<TriggerMethod>Distance</TriggerMethod>
<Track\>
`
//Creating TCX trackpoints via iterating across log.strokes
var startDate = new Date(exportItem.timeStampDate.toISOString())
for(let stroke = 0; stroke < exportItem.strokes.length-1; stroke += 2){
var timestamp = new Date(exportItem.timeStampDate.toISOString())
timestamp.setSeconds(startDate.getSeconds() + (exportItem.strokes[stroke].workTime.getMilliseconds() + exportItem.strokes[stroke].workTime.getSeconds()*1000 + (exportItem.strokes[stroke].workTime.getMinutes()*60000))/1000)
TCXcontent += ` <Trackpoint>
<Time>${timestamp.toISOString()}</Time>
<Position>
<LatitudeDegrees>${ergometerWidgets.mapWidget.distanceToMapPosition(exportItem.strokes[stroke].distance).latitude}</LatitudeDegrees>
<LongitudeDegrees>${ergometerWidgets.mapWidget.distanceToMapPosition(exportItem.strokes[stroke].distance).longitude}</LongitudeDegrees>
</Position>
<DistanceMeters>${exportItem.strokes[stroke].distance}</DistanceMeters>
<HeartRateBpm>
<Value>${exportItem.strokes[stroke].heartRate}</Value>
</HeartRateBpm>
<Cadence>${exportItem.strokes[stroke].strokesPerMinute}</Cadence>
<Extensions>
<ns3:TPX>
<ns3:Watts>${exportItem.strokes[stroke].power.toString()}</ns3:Watts>
</ns3:TPX>
</Extensions>
</Trackpoint>
`
}
// adding TCX ending content
TCXcontent += ` </Track>
</Lap>
<Creator xsi:type="Device_t">
<Name>--No GPS SELECTED--</Name>
<UnitId>0</UnitId>
<ProductID>0</ProductID>
<Version>
<VersionMajor>0</VersionMajor>
<VersionMinor>0</VersionMinor>
<BuildMajor>1</BuildMajor>
<BuildMinor>1</BuildMinor>
</Version>
</Creator>
</Activity>
</Activities>
<Author xsi:type="Application_t">
<Name>GOTOES STRAVA TOOLS</Name>
<Build>
<Version>
<VersionMajor>23</VersionMajor>
<VersionMinor>9</VersionMinor>
<BuildMajor>1</BuildMajor>
<BuildMinor>1</BuildMinor>
</Version>
</Build>
<LangID>en</LangID>
<PartNumber>1</PartNumber>
</Author>
</TrainingCenterDatabase>`
return TCXcontent
}
public init() {
pm3.log.registerCustomExport(this,"Demo export","demo.tcx","application/tcx",this.doExport.bind(this));
}
public remove() {
pm3.log.deRegisterCustomExport(this.doExport);
}
}
var plugin : ExamplePlugin;
plugin = new ExamplePlugin();
}
—
Reply to this email directly, view it on GitHub <#29 (comment)>, or unsubscribe <https://github.com/notifications/unsubscribe-auth/AAVG7NRHZZRN7AV2V7IXUELYUPH25AVCNFSM6AAAAABDLMULISVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTSNJTGIZTOMBTGQ>.
You are receiving this because you commented.
|
Made some improvements:
module joel_export_TCX { //make a name space to prevent mix ups
class ExamplePlugin extends ExternalPlugin {
private _oldExport : any;
public doExport(exportItem : pm3.WorkoutLogItem) : string {
//Forming first part of the TCX file
var TCXcontent = `<?xml version="1.0" encoding="UTF-8"?><TrainingCenterDatabase
xsi:schemaLocation="http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2 http://www.garmin.com/xmlschemas/TrainingCenterDatabasev2.xsd"
xmlns:ns5="http://www.garmin.com/xmlschemas/ActivityGoals/v1"
xmlns:ns3="http://www.garmin.com/xmlschemas/ActivityExtension/v2"
xmlns:ns2="http://www.garmin.com/xmlschemas/UserProfile/v2"
xmlns="http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ns4="http://www.garmin.com/xmlschemas/ProfileExtension/v1">
<Activities>
<Activity Sport="Other">
<Id>${exportItem.timeStampDate.toISOString()}</Id>
<Lap StartTime="${exportItem.timeStampDate.toISOString()}">
<TotalTimeSeconds>${exportItem.endDuration/1000}</TotalTimeSeconds>
<DistanceMeters>${exportItem.endDistance}</DistanceMeters>
<Calories>${Math.round(exportItem.totalCalories)}</Calories>
<TriggerMethod>Distance</TriggerMethod>
<Track\>
`
if (exportItem.strokes) {
//Creating TCX trackpoints via iterating across log.strokes
var startDate = new Date(exportItem.timeStampDate.toISOString());
var prefDistance=-1;
for(let i = 0; i < exportItem.strokes.length-1; i++){
var stroke=exportItem.strokes[i];
//make sure that we make some distance for an acurate speed calculation
if (stroke.distance>prefDistance+1) {
var timestamp = new Date(exportItem.timeStampDate.toISOString())
timestamp.setSeconds(startDate.getSeconds() + (stroke.workTime.getMilliseconds() + stroke.workTime.getSeconds()*1000 + (stroke.workTime.getMinutes()*60000))/1000)
//make sure there is a map os and if not do not add
var mapPos=ergometerWidgets.mapWidget?ergometerWidgets.mapWidget.distanceToMapPosition(stroke.distance):null;
TCXcontent += ` <Trackpoint>
<Time>${timestamp.toISOString()}</Time>
${mapPos?`<Position>
<LatitudeDegrees>${mapPos.latitude}</LatitudeDegrees>
<LongitudeDegrees>${mapPos.longitude}</LongitudeDegrees>
</Position>`:``}
<DistanceMeters>${stroke.distance}</DistanceMeters>
<HeartRateBpm>
<Value>${stroke.heartRate}</Value>
</HeartRateBpm>
<Cadence>${stroke.strokesPerMinute}</Cadence>
<Extensions>
<ns3:TPX>
<ns3:Watts>${stroke.power.toString()}</ns3:Watts>
</ns3:TPX>
</Extensions>
</Trackpoint>
`
}
prefDistance=stroke.distance
}
}
// adding TCX ending content
TCXcontent += ` </Track>
<Notes>${exportItem.description?exportItem.description:""}</Notes>
</Lap>
<Creator xsi:type="Device_t">
<Name>--No GPS SELECTED--</Name>
<UnitId>0</UnitId>
<ProductID>0</ProductID>
<Version>
<VersionMajor>0</VersionMajor>
<VersionMinor>0</VersionMinor>
<BuildMajor>1</BuildMajor>
<BuildMinor>1</BuildMinor>
</Version>
</Creator>
</Activity>
</Activities>
<Author xsi:type="Application_t">
<Name>GOTOES STRAVA TOOLS</Name>
<Build>
<Version>
<VersionMajor>23</VersionMajor>
<VersionMinor>9</VersionMinor>
<BuildMajor>1</BuildMajor>
<BuildMinor>1</BuildMinor>
</Version>
</Build>
<LangID>en</LangID>
<PartNumber>1</PartNumber>
</Author>
</TrainingCenterDatabase>`
return TCXcontent
}
public init() {
pm3.log.registerCustomExport(this,"Tcx export","workout.tcx","application/tcx",this.doExport);
}
public remove() {
pm3.log.deRegisterCustomExport(this.doExport);
}
}
var plugin : ExamplePlugin;
plugin = new ExamplePlugin();
}
… On 19 Feb 2024, at 23:37, joelbarrette ***@***.***> wrote:
Scratch what I said about the distance problems, I was able to fix it by changing how my for loop iterates. Here's the final code so far, I had to change the file type to TCX but other than that it's looking good:
module joel_export_TCX { //make a name space to prevent mix ups
class ExamplePlugin extends ExternalPlugin {
private _oldExport : any;
public doExport(exportItem : pm3.WorkoutLogItem) : string {
//Forming first part of the TCX file
var TCXcontent = `<?xml version="1.0" encoding="UTF-8"?><TrainingCenterDatabase
xsi:schemaLocation="http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2 http://www.garmin.com/xmlschemas/TrainingCenterDatabasev2.xsd"
xmlns:ns5="http://www.garmin.com/xmlschemas/ActivityGoals/v1"
xmlns:ns3="http://www.garmin.com/xmlschemas/ActivityExtension/v2"
xmlns:ns2="http://www.garmin.com/xmlschemas/UserProfile/v2"
xmlns="http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ns4="http://www.garmin.com/xmlschemas/ProfileExtension/v1">
<Activities>
<Activity Sport="Other">
<Id>${exportItem.timeStampDate.toISOString()}</Id>
<Lap StartTime="${exportItem.timeStampDate.toISOString()}">
<TotalTimeSeconds>${exportItem.endDuration/1000}</TotalTimeSeconds>
<DistanceMeters>${exportItem.distance}</DistanceMeters>
<TriggerMethod>Distance</TriggerMethod>
<Track\>
`
//Creating TCX trackpoints via iterating across log.strokes
var startDate = new Date(exportItem.timeStampDate.toISOString())
for(let stroke = 0; stroke < exportItem.strokes.length-1; stroke += 2){
var timestamp = new Date(exportItem.timeStampDate.toISOString())
timestamp.setSeconds(startDate.getSeconds() + (exportItem.strokes[stroke].workTime.getMilliseconds() + exportItem.strokes[stroke].workTime.getSeconds()*1000 + (exportItem.strokes[stroke].workTime.getMinutes()*60000))/1000)
TCXcontent += ` <Trackpoint>
<Time>${timestamp.toISOString()}</Time>
<Position>
<LatitudeDegrees>${ergometerWidgets.mapWidget.distanceToMapPosition(exportItem.strokes[stroke].distance).latitude}</LatitudeDegrees>
<LongitudeDegrees>${ergometerWidgets.mapWidget.distanceToMapPosition(exportItem.strokes[stroke].distance).longitude}</LongitudeDegrees>
</Position>
<DistanceMeters>${exportItem.strokes[stroke].distance}</DistanceMeters>
<HeartRateBpm>
<Value>${exportItem.strokes[stroke].heartRate}</Value>
</HeartRateBpm>
<Cadence>${exportItem.strokes[stroke].strokesPerMinute}</Cadence>
<Extensions>
<ns3:TPX>
<ns3:Watts>${exportItem.strokes[stroke].power.toString()}</ns3:Watts>
</ns3:TPX>
</Extensions>
</Trackpoint>
`
}
// adding TCX ending content
TCXcontent += ` </Track>
</Lap>
<Creator xsi:type="Device_t">
<Name>--No GPS SELECTED--</Name>
<UnitId>0</UnitId>
<ProductID>0</ProductID>
<Version>
<VersionMajor>0</VersionMajor>
<VersionMinor>0</VersionMinor>
<BuildMajor>1</BuildMajor>
<BuildMinor>1</BuildMinor>
</Version>
</Creator>
</Activity>
</Activities>
<Author xsi:type="Application_t">
<Name>GOTOES STRAVA TOOLS</Name>
<Build>
<Version>
<VersionMajor>23</VersionMajor>
<VersionMinor>9</VersionMinor>
<BuildMajor>1</BuildMajor>
<BuildMinor>1</BuildMinor>
</Version>
</Build>
<LangID>en</LangID>
<PartNumber>1</PartNumber>
</Author>
</TrainingCenterDatabase>`
return TCXcontent
}
public init() {
pm3.log.registerCustomExport(this,"Demo export","demo.tcx","application/tcx",this.doExport.bind(this));
}
public remove() {
pm3.log.deRegisterCustomExport(this.doExport);
}
}
var plugin : ExamplePlugin;
plugin = new ExamplePlugin();
}
—
Reply to this email directly, view it on GitHub <#29 (comment)>, or unsubscribe <https://github.com/notifications/unsubscribe-auth/AAVG7NRHZZRN7AV2V7IXUELYUPH25AVCNFSM6AAAAABDLMULISVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTSNJTGIZTOMBTGQ>.
You are receiving this because you commented.
|
View more improvements :
module joel_export_TCX { //make a name space to prevent mix ups
class ExamplePlugin extends ExternalPlugin {
private _oldExport : any;
public doExport(exportItem : pm3.WorkoutLogItem) : string {
//Forming first part of the TCX file
var TCXcontent = `<?xml version="1.0" encoding="UTF-8"?><TrainingCenterDatabase
xsi:schemaLocation="http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2 http://www.garmin.com/xmlschemas/TrainingCenterDatabasev2.xsd"
xmlns:ns5="http://www.garmin.com/xmlschemas/ActivityGoals/v1"
xmlns:ns3="http://www.garmin.com/xmlschemas/ActivityExtension/v2"
xmlns:ns2="http://www.garmin.com/xmlschemas/UserProfile/v2"
xmlns="http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ns4="http://www.garmin.com/xmlschemas/ProfileExtension/v1">
<Activities>
<Activity Sport="Other">
<Id>${exportItem.timeStampDate.toISOString()}</Id>
<Lap StartTime="${exportItem.timeStampDate.toISOString()}">
<TotalTimeSeconds>${exportItem.endDuration/1000}</TotalTimeSeconds>
<DistanceMeters>${exportItem.endDistance}</DistanceMeters>
<Calories>${Math.round(exportItem.totalCalories)}</Calories>
<TriggerMethod>Distance</TriggerMethod>
<Track\>
`
if (exportItem.strokes) {
//Creating TCX trackpoints via iterating across log.strokes
var startDate = new Date(exportItem.timeStampDate.getTime());
var prefDistance=-1;
for(let i = 0; i < exportItem.strokes.length-1; i++){
var stroke=exportItem.strokes[i];
//make sure that we make some distance for an acurate speed calculation
if (stroke.distance>prefDistance+1) {
var timestamp = new Date(exportItem.timeStampDate.getTime()+stroke.workTime.getTime());
//make sure there is a map os and if not do not add
var mapPos=ergometerWidgets.mapWidget?ergometerWidgets.mapWidget.distanceToMapPosition(stroke.distance):null;
TCXcontent += ` <Trackpoint>
<Time>${timestamp.toISOString()}</Time>
${mapPos?`<Position>
<LatitudeDegrees>${mapPos.latitude}</LatitudeDegrees>
<LongitudeDegrees>${mapPos.longitude}</LongitudeDegrees>
</Position>`:``}
<DistanceMeters>${stroke.distance}</DistanceMeters>
${stroke.heartRate>0?`<HeartRateBpm>
<Value>${stroke.heartRate}</Value>
</HeartRateBpm>`:``}
<Cadence>${stroke.strokesPerMinute}</Cadence>
<Extensions>
<ns3:TPX>
<ns3:Watts>${stroke.power.toString()}</ns3:Watts>
</ns3:TPX>
</Extensions>
</Trackpoint>
`
}
prefDistance=stroke.distance
}
}
// adding TCX ending content
TCXcontent += ` </Track>
<Notes>${utilities.htmlEncode(exportItem.description?exportItem.description:"") }</Notes>
</Lap>
<Creator xsi:type="Device_t">
<Name>--No GPS SELECTED--</Name>
<UnitId>0</UnitId>
<ProductID>0</ProductID>
<Version>
<VersionMajor>0</VersionMajor>
<VersionMinor>0</VersionMinor>
<BuildMajor>1</BuildMajor>
<BuildMinor>1</BuildMinor>
</Version>
</Creator>
</Activity>
</Activities>
<Author xsi:type="Application_t">
<Name>Ergometer Space</Name>
<Build>
<Version>
<VersionMajor>5</VersionMajor>
<VersionMinor>4</VersionMinor>
<BuildMajor>2</BuildMajor>
<BuildMinor>0</BuildMinor>
</Version>
</Build>
<LangID>en</LangID>
<PartNumber>1</PartNumber>
</Author>
</TrainingCenterDatabase>`
return TCXcontent
}
public init() {
pm3.log.registerCustomExport(this,"Tcx export","workout.tcx","application/tcx",this.doExport);
}
public remove() {
pm3.log.deRegisterCustomExport(this.doExport);
}
}
var plugin : ExamplePlugin;
plugin = new ExamplePlugin();
}
… On 19 Feb 2024, at 23:37, joelbarrette ***@***.***> wrote:
Scratch what I said about the distance problems, I was able to fix it by changing how my for loop iterates. Here's the final code so far, I had to change the file type to TCX but other than that it's looking good:
module joel_export_TCX { //make a name space to prevent mix ups
class ExamplePlugin extends ExternalPlugin {
private _oldExport : any;
public doExport(exportItem : pm3.WorkoutLogItem) : string {
//Forming first part of the TCX file
var TCXcontent = `<?xml version="1.0" encoding="UTF-8"?><TrainingCenterDatabase
xsi:schemaLocation="http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2 http://www.garmin.com/xmlschemas/TrainingCenterDatabasev2.xsd"
xmlns:ns5="http://www.garmin.com/xmlschemas/ActivityGoals/v1"
xmlns:ns3="http://www.garmin.com/xmlschemas/ActivityExtension/v2"
xmlns:ns2="http://www.garmin.com/xmlschemas/UserProfile/v2"
xmlns="http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ns4="http://www.garmin.com/xmlschemas/ProfileExtension/v1">
<Activities>
<Activity Sport="Other">
<Id>${exportItem.timeStampDate.toISOString()}</Id>
<Lap StartTime="${exportItem.timeStampDate.toISOString()}">
<TotalTimeSeconds>${exportItem.endDuration/1000}</TotalTimeSeconds>
<DistanceMeters>${exportItem.distance}</DistanceMeters>
<TriggerMethod>Distance</TriggerMethod>
<Track\>
`
//Creating TCX trackpoints via iterating across log.strokes
var startDate = new Date(exportItem.timeStampDate.toISOString())
for(let stroke = 0; stroke < exportItem.strokes.length-1; stroke += 2){
var timestamp = new Date(exportItem.timeStampDate.toISOString())
timestamp.setSeconds(startDate.getSeconds() + (exportItem.strokes[stroke].workTime.getMilliseconds() + exportItem.strokes[stroke].workTime.getSeconds()*1000 + (exportItem.strokes[stroke].workTime.getMinutes()*60000))/1000)
TCXcontent += ` <Trackpoint>
<Time>${timestamp.toISOString()}</Time>
<Position>
<LatitudeDegrees>${ergometerWidgets.mapWidget.distanceToMapPosition(exportItem.strokes[stroke].distance).latitude}</LatitudeDegrees>
<LongitudeDegrees>${ergometerWidgets.mapWidget.distanceToMapPosition(exportItem.strokes[stroke].distance).longitude}</LongitudeDegrees>
</Position>
<DistanceMeters>${exportItem.strokes[stroke].distance}</DistanceMeters>
<HeartRateBpm>
<Value>${exportItem.strokes[stroke].heartRate}</Value>
</HeartRateBpm>
<Cadence>${exportItem.strokes[stroke].strokesPerMinute}</Cadence>
<Extensions>
<ns3:TPX>
<ns3:Watts>${exportItem.strokes[stroke].power.toString()}</ns3:Watts>
</ns3:TPX>
</Extensions>
</Trackpoint>
`
}
// adding TCX ending content
TCXcontent += ` </Track>
</Lap>
<Creator xsi:type="Device_t">
<Name>--No GPS SELECTED--</Name>
<UnitId>0</UnitId>
<ProductID>0</ProductID>
<Version>
<VersionMajor>0</VersionMajor>
<VersionMinor>0</VersionMinor>
<BuildMajor>1</BuildMajor>
<BuildMinor>1</BuildMinor>
</Version>
</Creator>
</Activity>
</Activities>
<Author xsi:type="Application_t">
<Name>GOTOES STRAVA TOOLS</Name>
<Build>
<Version>
<VersionMajor>23</VersionMajor>
<VersionMinor>9</VersionMinor>
<BuildMajor>1</BuildMajor>
<BuildMinor>1</BuildMinor>
</Version>
</Build>
<LangID>en</LangID>
<PartNumber>1</PartNumber>
</Author>
</TrainingCenterDatabase>`
return TCXcontent
}
public init() {
pm3.log.registerCustomExport(this,"Demo export","demo.tcx","application/tcx",this.doExport.bind(this));
}
public remove() {
pm3.log.deRegisterCustomExport(this.doExport);
}
}
var plugin : ExamplePlugin;
plugin = new ExamplePlugin();
}
—
Reply to this email directly, view it on GitHub <#29 (comment)>, or unsubscribe <https://github.com/notifications/unsubscribe-auth/AAVG7NRHZZRN7AV2V7IXUELYUPH25AVCNFSM6AAAAABDLMULISVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTSNJTGIZTOMBTGQ>.
You are receiving this because you commented.
|
I think we also need to correct the start time:
module joel_export_TCX { //make a name space to prevent mix ups
class ExamplePlugin extends ExternalPlugin {
private _oldExport : any;
public doExport(exportItem : pm3.WorkoutLogItem) : string {
//Forming first part of the TCX file
var TCXcontent = `<?xml version="1.0" encoding="UTF-8"?><TrainingCenterDatabase
xsi:schemaLocation="http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2 http://www.garmin.com/xmlschemas/TrainingCenterDatabasev2.xsd"
xmlns:ns5="http://www.garmin.com/xmlschemas/ActivityGoals/v1"
xmlns:ns3="http://www.garmin.com/xmlschemas/ActivityExtension/v2"
xmlns:ns2="http://www.garmin.com/xmlschemas/UserProfile/v2"
xmlns="http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ns4="http://www.garmin.com/xmlschemas/ProfileExtension/v1">
<Activities>
<Activity Sport="Other">
<Id>${exportItem.timeStampDate.toISOString()}</Id>
<Lap StartTime="${exportItem.timeStampDate.toISOString()}">
<TotalTimeSeconds>${exportItem.endDuration/1000}</TotalTimeSeconds>
<DistanceMeters>${exportItem.endDistance}</DistanceMeters>
<Calories>${Math.round(exportItem.totalCalories)}</Calories>
<TriggerMethod>Distance</TriggerMethod>
<Track\>
`
if (exportItem.strokes) {
//Creating TCX trackpoints via iterating across log.strokes
//for ergometer space the timestamp is at the moment loged so the end, substract the duration
var startDate = exportItem.timeStampDate.getTime()-exportItem.endDuration;
var prefDistance=-1;
for(let i = 0; i < exportItem.strokes.length-1; i++){
var stroke=exportItem.strokes[i];
//make sure that we make some distance for an acurate speed calculation
if (stroke.distance>prefDistance+1) {
var timestamp = new Date(startDate+stroke.workTime.getTime());
//make sure there is a map os and if not do not add
var mapPos=ergometerWidgets.mapWidget?ergometerWidgets.mapWidget.distanceToMapPosition(stroke.distance):null;
TCXcontent += ` <Trackpoint>
<Time>${timestamp.toISOString()}</Time>
${mapPos?`<Position>
<LatitudeDegrees>${mapPos.latitude}</LatitudeDegrees>
<LongitudeDegrees>${mapPos.longitude}</LongitudeDegrees>
</Position>`:``}
<DistanceMeters>${stroke.distance}</DistanceMeters>
${stroke.heartRate>0?`<HeartRateBpm>
<Value>${stroke.heartRate}</Value>
</HeartRateBpm>`:``}
<Cadence>${stroke.strokesPerMinute}</Cadence>
<Extensions>
<ns3:TPX>
<ns3:Watts>${stroke.power.toString()}</ns3:Watts>
</ns3:TPX>
</Extensions>
</Trackpoint>
`
}
prefDistance=stroke.distance
}
}
// adding TCX ending content
TCXcontent += ` </Track>
<Notes>${utilities.htmlEncode(exportItem.description?exportItem.description:"") }</Notes>
</Lap>
<Creator xsi:type="Device_t">
<Name>--No GPS SELECTED--</Name>
<UnitId>0</UnitId>
<ProductID>0</ProductID>
<Version>
<VersionMajor>0</VersionMajor>
<VersionMinor>0</VersionMinor>
<BuildMajor>1</BuildMajor>
<BuildMinor>1</BuildMinor>
</Version>
</Creator>
</Activity>
</Activities>
<Author xsi:type="Application_t">
<Name>Ergometer Space</Name>
<Build>
<Version>
<VersionMajor>5</VersionMajor>
<VersionMinor>4</VersionMinor>
<BuildMajor>2</BuildMajor>
<BuildMinor>0</BuildMinor>
</Version>
</Build>
<LangID>en</LangID>
<PartNumber>1</PartNumber>
</Author>
</TrainingCenterDatabase>`
return TCXcontent
}
public init() {
pm3.log.registerCustomExport(this,"Tcx export","workout.tcx","application/tcx",this.doExport);
}
public remove() {
pm3.log.deRegisterCustomExport(this.doExport);
}
}
var plugin : ExamplePlugin;
plugin = new ExamplePlugin();
}
… On 19 Feb 2024, at 23:37, joelbarrette ***@***.***> wrote:
Scratch what I said about the distance problems, I was able to fix it by changing how my for loop iterates. Here's the final code so far, I had to change the file type to TCX but other than that it's looking good:
module joel_export_TCX { //make a name space to prevent mix ups
class ExamplePlugin extends ExternalPlugin {
private _oldExport : any;
public doExport(exportItem : pm3.WorkoutLogItem) : string {
//Forming first part of the TCX file
var TCXcontent = `<?xml version="1.0" encoding="UTF-8"?><TrainingCenterDatabase
xsi:schemaLocation="http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2 http://www.garmin.com/xmlschemas/TrainingCenterDatabasev2.xsd"
xmlns:ns5="http://www.garmin.com/xmlschemas/ActivityGoals/v1"
xmlns:ns3="http://www.garmin.com/xmlschemas/ActivityExtension/v2"
xmlns:ns2="http://www.garmin.com/xmlschemas/UserProfile/v2"
xmlns="http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ns4="http://www.garmin.com/xmlschemas/ProfileExtension/v1">
<Activities>
<Activity Sport="Other">
<Id>${exportItem.timeStampDate.toISOString()}</Id>
<Lap StartTime="${exportItem.timeStampDate.toISOString()}">
<TotalTimeSeconds>${exportItem.endDuration/1000}</TotalTimeSeconds>
<DistanceMeters>${exportItem.distance}</DistanceMeters>
<TriggerMethod>Distance</TriggerMethod>
<Track\>
`
//Creating TCX trackpoints via iterating across log.strokes
var startDate = new Date(exportItem.timeStampDate.toISOString())
for(let stroke = 0; stroke < exportItem.strokes.length-1; stroke += 2){
var timestamp = new Date(exportItem.timeStampDate.toISOString())
timestamp.setSeconds(startDate.getSeconds() + (exportItem.strokes[stroke].workTime.getMilliseconds() + exportItem.strokes[stroke].workTime.getSeconds()*1000 + (exportItem.strokes[stroke].workTime.getMinutes()*60000))/1000)
TCXcontent += ` <Trackpoint>
<Time>${timestamp.toISOString()}</Time>
<Position>
<LatitudeDegrees>${ergometerWidgets.mapWidget.distanceToMapPosition(exportItem.strokes[stroke].distance).latitude}</LatitudeDegrees>
<LongitudeDegrees>${ergometerWidgets.mapWidget.distanceToMapPosition(exportItem.strokes[stroke].distance).longitude}</LongitudeDegrees>
</Position>
<DistanceMeters>${exportItem.strokes[stroke].distance}</DistanceMeters>
<HeartRateBpm>
<Value>${exportItem.strokes[stroke].heartRate}</Value>
</HeartRateBpm>
<Cadence>${exportItem.strokes[stroke].strokesPerMinute}</Cadence>
<Extensions>
<ns3:TPX>
<ns3:Watts>${exportItem.strokes[stroke].power.toString()}</ns3:Watts>
</ns3:TPX>
</Extensions>
</Trackpoint>
`
}
// adding TCX ending content
TCXcontent += ` </Track>
</Lap>
<Creator xsi:type="Device_t">
<Name>--No GPS SELECTED--</Name>
<UnitId>0</UnitId>
<ProductID>0</ProductID>
<Version>
<VersionMajor>0</VersionMajor>
<VersionMinor>0</VersionMinor>
<BuildMajor>1</BuildMajor>
<BuildMinor>1</BuildMinor>
</Version>
</Creator>
</Activity>
</Activities>
<Author xsi:type="Application_t">
<Name>GOTOES STRAVA TOOLS</Name>
<Build>
<Version>
<VersionMajor>23</VersionMajor>
<VersionMinor>9</VersionMinor>
<BuildMajor>1</BuildMajor>
<BuildMinor>1</BuildMinor>
</Version>
</Build>
<LangID>en</LangID>
<PartNumber>1</PartNumber>
</Author>
</TrainingCenterDatabase>`
return TCXcontent
}
public init() {
pm3.log.registerCustomExport(this,"Demo export","demo.tcx","application/tcx",this.doExport.bind(this));
}
public remove() {
pm3.log.deRegisterCustomExport(this.doExport);
}
}
var plugin : ExamplePlugin;
plugin = new ExamplePlugin();
}
—
Reply to this email directly, view it on GitHub <#29 (comment)>, or unsubscribe <https://github.com/notifications/unsubscribe-auth/AAVG7NRHZZRN7AV2V7IXUELYUPH25AVCNFSM6AAAAABDLMULISVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTSNJTGIZTOMBTGQ>.
You are receiving this because you commented.
|
The next release will include the improved version. Can I mention your name in the credits? |
I have not received feedback for the last days, I have released the feature, so I close the issue. |
I'm looking to get data such as power, stroke rate and heart rate converted to a TCX file format so it can be exported to other programs like Garmin connect.
It's doable manually by exporting the CSV data and re-organizing the data, the biggest hurdle being the individual timestamps need to be calculated using the offsets.
Is this something that I could implement using the plugins?
Thanks,
Joel
The text was updated successfully, but these errors were encountered: