Readme update and logging improved

master
mgifos 8 years ago
parent 2481dc9952
commit 248e646137
  1. 92
      README.md
  2. 6
      src/main/scala/com.github.mgifos.workouts/GarminConnect.scala
  3. 6
      src/main/scala/com.github.mgifos.workouts/Main.scala
  4. 78
      src/test/resources/ultra-80k-runnersworld.csv

@ -1,20 +1,22 @@
# Workouts
The objectives of this project are to:
- enable easier notation for workouts (textual form)
- be able to specify weekly based training plans in e.g. spreadsheets that can be exported to CSV
- be able to import workouts from CSV file to Garmin Connect workout list
- be able to schedule imported workouts in Garmin Connect calendar automaticaly based on start/end date
# Quick plan
is a command line tool to define, import, schedule and share GarminConnect workouts i.e. weekly based training plans.
An example of a workout definition notation:
```sh
workout: run-fast
- warmup: 10:00 @ z2
workout: 15k, 3x3.2k @HMP
- warmup: 2km @z2
- repeat: 3
- run: 1.5km @ 5:10-4:40
- recover: 500m @ z2
- cooldown: 05:00
- run: 3200m @ 5:05-4:50
- recover: 800m @z2
- run: 1km @z2
- cooldown: lap-button
```
In CSV 1st row is reserved for heading, can be anything and the 1st column is reserved for a week number. The cells represent days and they are populated with workouts (definitions and references), so there's a limitation: a single work out per day/cell, for now. In case of the references, a workout needs to be defined first in one of the previous cells and then it can be referenced by name in the following cells.
and the tool's job is actually to translate it to this:
![15k workout](https://i.imgur.com/vxXNV7w.png)
## File format
The file format is a spreadsheet exported to csv format. The 1st row is reserved for heading, can be anything (you define your first day of a week etc.). The 1st column is reserved for a week number. The cells represent days and they are populated with workouts (definitions and references), so there's a limitation: a single workout per day/cell, for now. In case of the references, a workout needs to be defined first in one of the previous cells and then it can be referenced by name in the following cells.
An example of 2-weeks training plan, containing 2 workout definitions, 4 references and 6 training days in total:
@ -22,3 +24,69 @@ An example of 2-weeks training plan, containing 2 workout definitions, 4 referen
| ----:| --- | --- | --- | --- | --- | --- | --- |
| 1 | ``workout: run-fast``<br>``- warmup: 10:00 @ z2``<br>``- repeat: 3``<br>&nbsp;&nbsp;``- run: 1.5km @ 5:10-4:40``<br>&nbsp;&nbsp;``- recover: 500m @ z2``<br>``- cooldown: 05:00``|rest|rest|run-fast|rest|rest|rest|
| 2 | run-fast| ``workout: long-15`` <br> ``- run: 15 km @ z2``|rest|run-fast|rest|rest|long-15|
Checkout a [complete training plan for 80K ultra](https://docs.google.com/spreadsheets/d/1b1ZzrAFrjd-kvPq11zlbE2bWn2IQmUy0lBqIOFjqbwk/edit?usp=sharing). It was originally published in an article of Runner's world website - here's [the link](https://www.runnersworld.com/ultrarunning/the-ultimate-ultramarathon-training-plan).
## Command line options
```
quick-plan --help
quick-plan 0.x
Usage: quick-plan [import|schedule] [options] <file>
-e, --email <value> E-mail to login to Garmin Connect
-p, --password <value> Password to login to Garmin Connect
-d, --delete Delete all existing workouts with same names as the ones that are going to be imported.
--help prints this usage text
<file> File with a weekly based plan in CSV format
Command: import
Imports all workout definitions from CSV file. If it's omitted, it is will be on by default.
Command: schedule [options]
Schedules your weekly plan defined in CSV in Garmin Connect calendar, starting from the first day of first week or ending on the last day of the last week. Either start or end date must be entered so the scheduling can be done properly. In case both are entered, start date has priority. All dates have to be entered in ISO date format e.g. '2018-03-24'.
-s, --start <value> Date of the first day of the first week of the plan
-n, --end <value> Date of the last day of the last week of the plan
EXAMPLES
Schedules ultra 80k plan targeting 28-4-2018 for a race day
quick-plan schedule -n 2018-04-29 -d -e your-mail-address@example.com ultra-80k-runnersworld.csv
```
## Workout notation
The reserved keywords of the notation are: workout, warmup, cooldown, run, repeat, recover and lap-button.
**`workout`** := `<header> <step>+`
**`<header>`** := `workout: <name>`
**`<step>`** := `<newline> - <step-def>*`
**`<step-def>`** := `<simple-step> | <repetition-step> `
**`<repetition-step>`** := `repeat: <count> <step>+`
**`<simple-step>`** := `- (warmup | cooldown | run | recover): <duration> [@ <target>]`
**`<duration>`** := `<distance-duration> | <time-duration> | lap-button`
**`<distance-duration>`** := `<number> (km | m | mi)`
**`<time-duration>`** := `<minutes>:<seconds>`
**`<target`>** := `<zone-target> | <pace-target>`
**`<zone-target`>** := `z[1-6]`
**`<pace-target`>** := `<pace> - <pace>`
**`<pace`>** := `<minutes>:<seconds>`
**`<minutes`>** := `\d{1,2}`
**`<seconds`>** := `\d{2}`

@ -68,7 +68,7 @@ class GarminConnect(email: String, password: String)(implicit system: ActorSyste
if res.status == OK
json <- res.entity.toStrict(10.seconds).map(_.data.utf8String)
} yield {
log.info(s" '$workout'")
log.info(s" $workout")
GarminWorkout(workout, Json.parse(json).\("workoutId").as[Long])
}
}
@ -97,7 +97,7 @@ class GarminConnect(email: String, password: String)(implicit system: ActorSyste
log.info("\nDeleting workouts:")
pairs.map {
case (workout, id) =>
val label = s"'$workout' -> $id"
val label = s"$workout -> $id"
label -> Post(s"https://connect.garmin.com/modern/proxy/workout-service/workout/$id")
.withHeaders(session.headers
:+ Referer("https://connect.garmin.com/modern/workouts")
@ -126,7 +126,7 @@ class GarminConnect(email: String, password: String)(implicit system: ActorSyste
Source(spec).map {
case (date, gw) =>
log.debug(s"Making $date -> $gw")
s"$date -> '${gw.name}'" -> Post(s"https://connect.garmin.com/modern/proxy/workout-service/schedule/${gw.id}")
s"$date -> ${gw.name}" -> Post(s"https://connect.garmin.com/modern/proxy/workout-service/schedule/${gw.id}")
.withHeaders(session.headers
:+ Referer("https://connect.garmin.com/modern/calendar")
:+ RawHeader("NK", "NT"))

@ -115,7 +115,7 @@ object Main extends App {
} yield {
log.info("\nStatistics:")
maybeDeleteMessage.foreach(msg => log.info(" " + msg))
log.info(s" ${garminWorkouts.length} workouts has been imported to Garmin Connect")
log.info(s" ${garminWorkouts.length} imported")
maybeScheduleMessage.foreach(msg => log.info(" " + msg))
}
}
@ -125,7 +125,7 @@ object Main extends App {
*/
private def deleteWorkoutsTask(workouts: Seq[String])(implicit config: Config, garmin: GarminConnect): Future[Option[String]] = {
if (config.delete)
garmin.deleteWorkouts(workouts).map(c => Some(s"$c workouts is deleted"))
garmin.deleteWorkouts(workouts).map(c => Some(s"$c deleted"))
else
Future.successful(None)
}
@ -143,7 +143,7 @@ object Main extends App {
val spec = plan.get.zipWithIndex.collect {
case (Some(ref), day) if !start.plusDays(day).isBefore(LocalDate.now()) => start.plusDays(day) -> woMap(ref.name)
}.to[Seq]
garmin.schedule(spec).map(c => Some(s"$c workouts is scheduled"))
garmin.schedule(spec).map(c => Some(s"$c scheduled"))
} else
Future.successful(None)
}

@ -4,87 +4,113 @@ WEEK,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday,Estimated km,,Dura
- repeat: 4
- run: 1600m @ 5:00-4:30
- recover: 900m @z2
- cooldown: 2km","workout: 8k jog
- run: 8km @z2","workout: 11-15k, middle 5k @MP
- run: 2km
- cooldown: lap-button","workout: 8k jog
- run: 8km @z2
- cooldown: lap-button","workout: 11-15k, middle 5k @MP
- warmup: 4km @z2
- run: 5km @ 5:40-5:30
- cooldown: 6km @z2",,"workout: 1.5h run
- run: 90:00","workout: 3h run
- run: 180:00",78.0,,0:10:00,1.7,1.0
- run: 6km @z2
- cooldown: lap-button",,"workout: 1.5h run
- run: 90:00
- cooldown: lap-button","workout: 3h run
- run: 180:00
- cooldown: lap-button",78.0,,0:10:00,1.7,1.0
2,,"14k, 4x 1.6k @TMP",8k jog,"11-15k, middle 5k @MP",,1.5h run,3h run,78.0,,0:15:00,2.5,1.6
3,,"workout: 14k, 2x1.6k @HMP
- warmup: 4km @z2
- repeat: 2
- run: 1.6km @ 5:05-4:50
- recover: 1.4km @z2
- cooldown: 4km @z2",8k jog,"11-15k, middle 5k @MP",,"workout: 2h run
- run 120:00","workout: 3.5h run
- run: 210:00",90.0,,0:30:00,5.0,3.1
- run: 4km @z2
- cooldown: lap-button",8k jog,"11-15k, middle 5k @MP",,"workout: 2h run
- run 120:00
- cooldown: lap-button","workout: 3.5h run
- run: 210:00
- cooldown: lap-button",90.0,,0:30:00,5.0,3.1
4,,"workout: 10k, 3x1.6k @TMP
- warmup: 1500m @z2
- repeat: 3
- run: 1600m @ 5:00-4:30
- recover: 900m @z2
- cooldown: 1km",8k jog,"workout: 10k, middle 3.2k @MP
- run: 1km @z2
- cooldown: lap-button",8k jog,"workout: 10k, middle 3.2k @MP
- warmup: 4km @z2
- run: 3200m @ 5:40-5:30
- cooldown: 2800m @z2",,1.5h run,2h run,63.0,,0:40:00,6.7,4.1
- run: 2800m @z2
- cooldown: lap-button",,1.5h run,2h run,63.0,,0:40:00,6.7,4.1
5,,"workout: 15k, 6x1.6k @TMP
- warmup: 2km @z2
- repeat: 6
- run: 1600m @ 5:00-4:30
- recover: 400m @z2
- cooldown: 1km",8k jog,"workout: 15k, middle 5k @MP
- run: 1km
- cooldown: lap-button",8k jog,"workout: 15k, middle 5k @MP
- warmup: 5km @z2
- run: 5km @ 5:40-5:30
- cooldown: 5km @z2",,"workout: 3.5-4h run
- run 225:00",3h run,104.7,,0:45:00,7.5,4.7
- run: 5km @z2
- cooldown: lap-button",,"workout: 3.5-4h run
- run 225:00
- cooldown: lap-button",3h run,104.7,,0:45:00,7.5,4.7
6,,"15k, 6x1.6k @TMP",8k jog,"15k, middle 5k @MP",,3.5-4h run,3h run,104.7,,0:50:00,8.3,5.2
7,,"workout: 15k, 6x1.6k @HMP
- warmup: 2km @z2
- repeat: 6
- run: 1600m @ 5:05-4:50
- recover: 400m @z2
- cooldown: 1km",8k jog,"15k, middle 5k @MP",,3.5-4h run,"workout: 3h run, last @MP
- run: 1km
- cooldown: lap-button",8k jog,"15k, middle 5k @MP",,3.5-4h run,"workout: 3h run, last @MP
- run: 120:00
- run: 60:00 @ 5:40-5:30",104.7,,1:00:00,10.0,6.2
- run: 60:00 @ 5:40-5:30
- cooldown: lap-button",104.7,,1:00:00,10.0,6.2
8,,"workout: 15k, 3x3.2k @HMP
- warmup: 2km @z2
- repeat: 3
- run: 3200m @ 5:05-4:50
- recover: 800m @z2
- cooldown: 1km",8k jog,"15k, middle 5k @MP",,2h run,"workout: 2.5h run
- run: 150:00",83.0,,1:20:00,13.3,8.3
- run: 1km @z2
- cooldown: lap-button",8k jog,"15k, middle 5k @MP",,2h run,"workout: 2.5h run
- run: 150:00
- cooldown: lap-button",83.0,,1:20:00,13.3,8.3
9,,"15k, 6x1.6k @TMP",8k jog,"15k, middle 5k @MP",,"workout: 4h run
- run: 240:00","workout: 3.5h run, last @MP
- run: 240:00
- cooldown: lap-button","workout: 3.5h run, last @MP
- run: 150:00
- run: 60:00 @ 5:40-5:30",113.0,,1:30:00,15.0,9.3
- run: 60:00 @ 5:40-5:30
- cooldown: lap-button",113.0,,1:30:00,15.0,9.3
10,,"15k, 6x1.6k @TMP",8k jog,"15k, middle 5k @MP",,4-hour run,"3.5h run, last @MP",113.0,,1:45:00,17.5,10.9
11,,"15k, 3x3.2k @HMP",8k jog,"15k, middle 5k @MP",,2.5h run,3h run,93.0,,2:00:00,20.0,12.4
12,,"15k, 6x1.6k @TMP",8k jog,"15k, middle 5k @MP",,4h run,"workout: 5h run
- run: 300:00",128.0,,2:30:00,25.0,15.5
- run: 300:00
- cooldown: lap-button",128.0,,2:30:00,25.0,15.5
13,,"15k, 6x1.6k @TMP",8k jog,"15k, middle 5k @MP",,4h run,5h run,128.0,,3:00:00,30.0,18.6
14,,"workout: 15k, 4x1.6k @TMP
- warmup: 3km @z2
- repeat: 2
- run: 1600m @ 5:00-4:30
- recover: 1400m @z2
- cooldown: 1km",8k jog,"15k, middle 5k @MP",,2h run,2h run,78.0,,3:30:00,35.0,21.7
- run: 1km @z2
- cooldown: lap-button",8k jog,"15k, middle 5k @MP",,2h run,2h run,78.0,,3:30:00,35.0,21.7
15,,"workout: 11k, 3x1.6k @MP
- warmup: 1.5km @z2
- repeat: 3
- run: 1600m @ 5:40-5:30
- recover: 1400m @z2
- cooldown: 500m",8k jog,"workout: 11k, middle 5k @MP
- run: 500m @z2
- cooldown: lap-button",8k jog,"workout: 11k, middle 5k @MP
- warmup: 3km @z2
- run: 5km @ 5:40-5:30
- cooldown: 3km @z2",,1.5h run,"workout: easy 1h jog
- run: 60:00",55.0,,4:00:00,40.0,24.8
- run: 3km @z2
- cooldown: lap-button",,1.5h run,"workout: easy 1h jog
- run: 60:00
- cooldown: lap-button",55.0,,4:00:00,40.0,24.8
16,,"workout: 10k, middle 5k @HMP
- warmup: 3km @z2
- run: 5km @ 5:05-4:30
- cooldown: 2km @z2",8k jog,"workout: easy 5k jog
- run: 5km",,80k race,Rest. (Duh.),103.0,,5:00:00,50.0,31.1
- run: 2km @z2
- cooldown: lap-button",8k jog,"workout: easy 5k jog
- run: 5km
- cooldown: lap-button",,Race day!,,103.0,,5:00:00,50.0,31.1
,,,,,,,,"1,517.0",,,,
,TMP,16k pace,,,,,,,,,,
,HMP,Half Marathon Pace,,,,,Avg min/km,0:06:00,,,,

1 WEEK Monday Tuesday Wednesday Thursday Friday Saturday Sunday Estimated km Duration Avg km Miles
4 3 workout: 14k, 2x1.6k @HMP - warmup: 4km @z2 - repeat: 2 - run: 1.6km @ 5:05-4:50 - recover: 1.4km @z2 - cooldown: 4km @z2 workout: 14k, 2x1.6k @HMP - warmup: 4km @z2 - repeat: 2 - run: 1.6km @ 5:05-4:50 - recover: 1.4km @z2 - run: 4km @z2 - cooldown: lap-button 8k jog 11-15k, middle 5k @MP workout: 2h run - run 120:00 workout: 2h run - run 120:00 - cooldown: lap-button workout: 3.5h run - run: 210:00 workout: 3.5h run - run: 210:00 - cooldown: lap-button 90.0 0:30:00 5.0 3.1
5 4 workout: 10k, 3x1.6k @TMP - warmup: 1500m @z2 - repeat: 3 - run: 1600m @ 5:00-4:30 - recover: 900m @z2 - cooldown: 1km workout: 10k, 3x1.6k @TMP - warmup: 1500m @z2 - repeat: 3 - run: 1600m @ 5:00-4:30 - recover: 900m @z2 - run: 1km @z2 - cooldown: lap-button 8k jog workout: 10k, middle 3.2k @MP - warmup: 4km @z2 - run: 3200m @ 5:40-5:30 - cooldown: 2800m @z2 workout: 10k, middle 3.2k @MP - warmup: 4km @z2 - run: 3200m @ 5:40-5:30 - run: 2800m @z2 - cooldown: lap-button 1.5h run 2h run 63.0 0:40:00 6.7 4.1
6 5 workout: 15k, 6x1.6k @TMP - warmup: 2km @z2 - repeat: 6 - run: 1600m @ 5:00-4:30 - recover: 400m @z2 - cooldown: 1km workout: 15k, 6x1.6k @TMP - warmup: 2km @z2 - repeat: 6 - run: 1600m @ 5:00-4:30 - recover: 400m @z2 - run: 1km - cooldown: lap-button 8k jog workout: 15k, middle 5k @MP - warmup: 5km @z2 - run: 5km @ 5:40-5:30 - cooldown: 5km @z2 workout: 15k, middle 5k @MP - warmup: 5km @z2 - run: 5km @ 5:40-5:30 - run: 5km @z2 - cooldown: lap-button workout: 3.5-4h run - run 225:00 workout: 3.5-4h run - run 225:00 - cooldown: lap-button 3h run 104.7 0:45:00 7.5 4.7
7 6 15k, 6x1.6k @TMP 8k jog 15k, middle 5k @MP 3.5-4h run 3h run 104.7 0:50:00 8.3 5.2
8 7 workout: 15k, 6x1.6k @HMP - warmup: 2km @z2 - repeat: 6 - run: 1600m @ 5:05-4:50 - recover: 400m @z2 - cooldown: 1km workout: 15k, 6x1.6k @HMP - warmup: 2km @z2 - repeat: 6 - run: 1600m @ 5:05-4:50 - recover: 400m @z2 - run: 1km - cooldown: lap-button 8k jog 15k, middle 5k @MP 3.5-4h run workout: 3h run, last @MP - run: 120:00 - run: 60:00 @ 5:40-5:30 workout: 3h run, last @MP - run: 120:00 - run: 60:00 @ 5:40-5:30 - cooldown: lap-button 104.7 1:00:00 10.0 6.2
9 8 workout: 15k, 3x3.2k @HMP - warmup: 2km @z2 - repeat: 3 - run: 3200m @ 5:05-4:50 - recover: 800m @z2 - run: 1km @z2 - cooldown: lap-button 8k jog 15k, middle 5k @MP 2h run workout: 2.5h run - run: 150:00 - cooldown: lap-button 83.0 1:20:00 13.3 8.3
10 9 15k, 6x1.6k @TMP 8k jog 15k, middle 5k @MP workout: 4h run - run: 240:00 - cooldown: lap-button workout: 3.5h run, last @MP - run: 150:00 - run: 60:00 @ 5:40-5:30 - cooldown: lap-button 113.0 1:30:00 15.0 9.3
11 8 10 workout: 15k, 3x3.2k @HMP - warmup: 2km @z2 - repeat: 3 - run: 3200m @ 5:05-4:50 - recover: 800m @z2 - cooldown: 1km 15k, 6x1.6k @TMP 8k jog 15k, middle 5k @MP 2h run 4-hour run workout: 2.5h run - run: 150:00 3.5h run, last @MP 83.0 113.0 1:20:00 1:45:00 13.3 17.5 8.3 10.9
12 9 11 15k, 6x1.6k @TMP 15k, 3x3.2k @HMP 8k jog 15k, middle 5k @MP workout: 4h run - run: 240:00 2.5h run workout: 3.5h run, last @MP - run: 150:00 - run: 60:00 @ 5:40-5:30 3h run 113.0 93.0 1:30:00 2:00:00 15.0 20.0 9.3 12.4
13 10 12 15k, 6x1.6k @TMP 8k jog 15k, middle 5k @MP 4-hour run 4h run 3.5h run, last @MP workout: 5h run - run: 300:00 - cooldown: lap-button 113.0 128.0 1:45:00 2:30:00 17.5 25.0 10.9 15.5
14 11 13 15k, 3x3.2k @HMP 15k, 6x1.6k @TMP 8k jog 15k, middle 5k @MP 2.5h run 4h run 3h run 5h run 93.0 128.0 2:00:00 3:00:00 20.0 30.0 12.4 18.6
15 12 14 15k, 6x1.6k @TMP workout: 15k, 4x1.6k @TMP - warmup: 3km @z2 - repeat: 2 - run: 1600m @ 5:00-4:30 - recover: 1400m @z2 - run: 1km @z2 - cooldown: lap-button 8k jog 15k, middle 5k @MP 4h run 2h run workout: 5h run - run: 300:00 2h run 128.0 78.0 2:30:00 3:30:00 25.0 35.0 15.5 21.7
16 15 workout: 11k, 3x1.6k @MP - warmup: 1.5km @z2 - repeat: 3 - run: 1600m @ 5:40-5:30 - recover: 1400m @z2 - run: 500m @z2 - cooldown: lap-button 8k jog workout: 11k, middle 5k @MP - warmup: 3km @z2 - run: 5km @ 5:40-5:30 - run: 3km @z2 - cooldown: lap-button 1.5h run workout: easy 1h jog - run: 60:00 - cooldown: lap-button 55.0 4:00:00 40.0 24.8
17 16 workout: 10k, middle 5k @HMP - warmup: 3km @z2 - run: 5km @ 5:05-4:30 - run: 2km @z2 - cooldown: lap-button 8k jog workout: easy 5k jog - run: 5km - cooldown: lap-button Race day! 103.0 5:00:00 50.0 31.1
18 1,517.0
19 13 TMP 15k, 6x1.6k @TMP 16k pace 8k jog 15k, middle 5k @MP 4h run 5h run 128.0 3:00:00 30.0 18.6
20 14 HMP workout: 15k, 4x1.6k @TMP - warmup: 3km @z2 - repeat: 2 - run: 1600m @ 5:00-4:30 - recover: 1400m @z2 - cooldown: 1km Half Marathon Pace 8k jog 15k, middle 5k @MP 2h run 2h run Avg min/km 78.0 0:06:00 3:30:00 35.0 21.7
21 15 MP workout: 11k, 3x1.6k @MP - warmup: 1.5km @z2 - repeat: 3 - run: 1600m @ 5:40-5:30 - recover: 1400m @z2 - cooldown: 500m Marathon Pace 8k jog workout: 11k, middle 5k @MP - warmup: 3km @z2 - run: 5km @ 5:40-5:30 - cooldown: 3km @z2 1.5h run workout: easy 1h jog - run: 60:00 55.0 4:00:00 40.0 24.8
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
Loading…
Cancel
Save