postrunner 0.12.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/lib/postrunner/Activity.rb +1 -1
- data/lib/postrunner/ActivitySummary.rb +11 -1
- data/lib/postrunner/ChartView.rb +8 -0
- data/lib/postrunner/FFS_Activity.rb +1 -1
- data/lib/postrunner/FFS_Device.rb +3 -2
- data/lib/postrunner/FitFileStore.rb +62 -5
- data/lib/postrunner/Main.rb +11 -4
- data/lib/postrunner/UserProfileView.rb +20 -8
- data/lib/postrunner/version.rb +2 -2
- data/postrunner.gemspec +2 -2
- data/spec/FitFileStore_spec.rb +7 -7
- metadata +7 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: bb8a80028ee50a8f543d589b44fd41523208483a1743d29ec86e37525ff84a13
|
4
|
+
data.tar.gz: 9834c6dc556e9e118fca144a8edd33e9cecc51eb9bc4487d43218973f5dae719
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8544b0aca1e86a9ca4e90aa437684a9fc56ac925cefe115ac9453816d1373242fcf6aa94d86ea779ea947ebb982b318141c45df43197d77a78b2375aeb5f6724
|
7
|
+
data.tar.gz: d5354f1f321685cb7181c75cee537d36695bddb0cecea175cd703de678af9055db10e089740f6719f1c6097e3fc2a2713951ae396b558b3ffc39a5bbfbe9f722
|
data/lib/postrunner/Activity.rb
CHANGED
@@ -316,7 +316,7 @@ module PostRunner
|
|
316
316
|
if zone.type == 18
|
317
317
|
total_time = 0.0
|
318
318
|
if zone.time_in_hr_zone
|
319
|
-
zone.time_in_hr_zone.each { |tiz| total_time += tiz }
|
319
|
+
zone.time_in_hr_zone.each { |tiz| total_time += tiz if tiz }
|
320
320
|
end
|
321
321
|
break if total_time <= 0.0
|
322
322
|
if zone.heart_rate_zones
|
@@ -354,12 +354,22 @@ module PostRunner
|
|
354
354
|
def local_value(fdr, field, format, units)
|
355
355
|
unit = units[@unit_system]
|
356
356
|
value = fdr.get_as(field, unit)
|
357
|
+
if value.nil? && field == 'avg_speed'
|
358
|
+
# New fit files used 'enhanced_avg_speed' instead of the older
|
359
|
+
# 'avg_speed'.
|
360
|
+
value = fdr.get_as('enhanced_avg_speed', unit)
|
361
|
+
end
|
357
362
|
return '-' unless value
|
358
363
|
"#{format % [value, unit]}"
|
359
364
|
end
|
360
365
|
|
361
366
|
def pace(fdr, field, show_unit = true)
|
362
367
|
speed = fdr.get(field)
|
368
|
+
if speed.nil? && field == 'avg_speed'
|
369
|
+
# New fit files used 'enhanced_avg_speed' instead of the older
|
370
|
+
# 'avg_speed'.
|
371
|
+
speed = fdr.get('enhanced_avg_speed')
|
372
|
+
end
|
363
373
|
case @unit_system
|
364
374
|
when :metric
|
365
375
|
"#{speedToPace(speed)}#{show_unit ? ' min/km' : ''}"
|
data/lib/postrunner/ChartView.rb
CHANGED
@@ -73,6 +73,14 @@ module PostRunner
|
|
73
73
|
:colors => '#900000',
|
74
74
|
:show => false
|
75
75
|
},
|
76
|
+
{
|
77
|
+
:id => 'respiration_rate',
|
78
|
+
:label => 'Respiration Rate',
|
79
|
+
:unit => 'brpm',
|
80
|
+
:graph => :line_graph,
|
81
|
+
:colors => '#9cd6ef',
|
82
|
+
:show => true
|
83
|
+
},
|
76
84
|
{
|
77
85
|
:id => 'performance_condition',
|
78
86
|
:label => 'Performance Condition',
|
@@ -3,7 +3,7 @@
|
|
3
3
|
#
|
4
4
|
# = FFS_Device.rb -- PostRunner - Manage the data from your Garmin sport devices.
|
5
5
|
#
|
6
|
-
# Copyright (c) 2015, 2016, 2018 by Chris Schlaeger <cs@taskjuggler.org>
|
6
|
+
# Copyright (c) 2015, 2016, 2018, 2020 by Chris Schlaeger <cs@taskjuggler.org>
|
7
7
|
#
|
8
8
|
# This program is free software; you can redistribute it and/or modify
|
9
9
|
# it under the terms of version 2 of the GNU General Public License as
|
@@ -83,7 +83,8 @@ module PostRunner
|
|
83
83
|
return nil
|
84
84
|
end
|
85
85
|
else
|
86
|
-
# Don't add the entity if has deleted before and overwrite isn't
|
86
|
+
# Don't add the entity if it has deleted before and overwrite isn't
|
87
|
+
# true.
|
87
88
|
path = @store['file_store'].fit_file_dir(File.basename(fit_file_name),
|
88
89
|
long_uid, type)
|
89
90
|
fq_fit_file_name = File.join(path, File.basename(fit_file_name))
|
@@ -44,7 +44,7 @@ module PostRunner
|
|
44
44
|
# Setup non-persistent variables.
|
45
45
|
def restore
|
46
46
|
@data_dir = @store['config']['data_dir']
|
47
|
-
# Ensure that we have
|
47
|
+
# Ensure that we have a Hash in the store to hold all known devices.
|
48
48
|
@store['devices'] = @store.new(PEROBS::Hash) unless @store['devices']
|
49
49
|
|
50
50
|
@devices_dir = File.join(@data_dir, 'devices')
|
@@ -69,8 +69,58 @@ module PostRunner
|
|
69
69
|
end
|
70
70
|
|
71
71
|
# Version upgrade logic.
|
72
|
-
def handle_version_update
|
73
|
-
|
72
|
+
def handle_version_update(from_version, to_version)
|
73
|
+
if from_version <= Gem::Version.new('0.12.0')
|
74
|
+
# PostRunner up until version 0.12.0 was using a long_uid with
|
75
|
+
# manufacturer name and product name. This was a bad idea since unknown
|
76
|
+
# devices were resolved to their numerical ID. In case the unknown ID
|
77
|
+
# was later added to the dictionary in fit4ruby version update, it
|
78
|
+
# resolved to its name and the device was recognized as a new device.
|
79
|
+
# Versions after 0.12.0 only use the numerical versions for the device
|
80
|
+
# long_uid and directory names.
|
81
|
+
uid_remap = {}
|
82
|
+
@store['devices'].each do |uid, device|
|
83
|
+
old_uid = uid
|
84
|
+
|
85
|
+
if (first_activity = device.activities.first)
|
86
|
+
first_activity.load_fit_file
|
87
|
+
if (fit_activity = first_activity.fit_activity)
|
88
|
+
if (device_info = fit_activity.device_infos.first)
|
89
|
+
new_uid = "#{device_info.numeric_manufacturer}-" +
|
90
|
+
"#{device_info.numeric_product}-#{device_info.serial_number}"
|
91
|
+
|
92
|
+
uid_remap[old_uid] = new_uid
|
93
|
+
puts first_activity.fit_file_name
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
@store.transaction do
|
100
|
+
pwd = Dir.pwd
|
101
|
+
base_dir_name = @store['config']['devices_dir']
|
102
|
+
Dir.chdir(base_dir_name)
|
103
|
+
|
104
|
+
uid_remap.each do |old_uid, new_uid|
|
105
|
+
if Dir.exist?(old_uid) && !Dir.exist?(new_uid) &&
|
106
|
+
!File.symlink?(old_uid)
|
107
|
+
# Rename the directory from the old (string) scheme to the
|
108
|
+
# new numeric scheme.
|
109
|
+
FileUtils.mv(old_uid, new_uid)
|
110
|
+
# Create a symbolic link with that points the old name to
|
111
|
+
# the new name.
|
112
|
+
File.symlink(new_uid, old_uid)
|
113
|
+
end
|
114
|
+
|
115
|
+
# Now update the long_uid in the FFS_Device object
|
116
|
+
@store['devices'][new_uid] = device = @store['devices'][old_uid]
|
117
|
+
device.long_uid = new_uid
|
118
|
+
@store['devices'].delete(old_uid)
|
119
|
+
end
|
120
|
+
|
121
|
+
Dir.chdir(pwd)
|
122
|
+
end
|
123
|
+
end
|
74
124
|
end
|
75
125
|
|
76
126
|
# Add a file to the store.
|
@@ -95,7 +145,8 @@ module PostRunner
|
|
95
145
|
# Generate a String that uniquely identifies the device that generated
|
96
146
|
# the FIT file.
|
97
147
|
id = extract_fit_file_id(fit_entity)
|
98
|
-
long_uid = "#{id[:
|
148
|
+
long_uid = "#{id[:numeric_manufacturer]}-" +
|
149
|
+
"#{id[:numeric_product]}-#{id[:serial_number]}"
|
99
150
|
|
100
151
|
# Make sure the device that created the FIT file is properly registered.
|
101
152
|
device = register_device(long_uid)
|
@@ -187,6 +238,7 @@ module PostRunner
|
|
187
238
|
@store['records'].generate_html_reports
|
188
239
|
generate_html_index_pages
|
189
240
|
end
|
241
|
+
|
190
242
|
# Determine the right directory for the given FIT file. The resulting path
|
191
243
|
# looks something like /home/user/.postrunner/devices/garmin-fenix3-1234/
|
192
244
|
# activity/5A.
|
@@ -462,6 +514,8 @@ module PostRunner
|
|
462
514
|
return {
|
463
515
|
:manufacturer => di.manufacturer,
|
464
516
|
:product => di.garmin_product || di.product,
|
517
|
+
:numeric_manufacturer => di.numeric_manufacturer,
|
518
|
+
:numeric_product => di.numeric_product,
|
465
519
|
:serial_number => di.serial_number
|
466
520
|
}
|
467
521
|
end
|
@@ -483,6 +537,8 @@ module PostRunner
|
|
483
537
|
return {
|
484
538
|
:manufacturer => fid.manufacturer,
|
485
539
|
:product => fid.garmin_product || fid.product,
|
540
|
+
:numeric_manufacturer => di.numeric_manufacturer,
|
541
|
+
:numeric_product => di.numeric_product,
|
486
542
|
:serial_number => fid.serial_number
|
487
543
|
}
|
488
544
|
end
|
@@ -502,7 +558,8 @@ module PostRunner
|
|
502
558
|
@store.new(FFS_Device, short_uid, long_uid)
|
503
559
|
|
504
560
|
# Create the directory to store the FIT files of this device.
|
505
|
-
create_directory(File.join(@devices_dir, long_uid),
|
561
|
+
create_directory(File.join(@devices_dir, long_uid),
|
562
|
+
long_uid)
|
506
563
|
end
|
507
564
|
|
508
565
|
@store['devices'][long_uid]
|
data/lib/postrunner/Main.rb
CHANGED
@@ -107,7 +107,7 @@ module PostRunner
|
|
107
107
|
|
108
108
|
opts.separator <<"EOT"
|
109
109
|
|
110
|
-
Copyright (c) 2014, 2015, 2016, 2017 by Chris Schlaeger
|
110
|
+
Copyright (c) 2014, 2015, 2016, 2017, 2018, 2019, 2020 by Chris Schlaeger
|
111
111
|
|
112
112
|
This program is free software; you can redistribute it and/or modify it under
|
113
113
|
the terms of version 2 of the GNU General Public License as published by the
|
@@ -597,10 +597,17 @@ EOT
|
|
597
597
|
|
598
598
|
def handle_version_update
|
599
599
|
if @db['config']['version'] != VERSION
|
600
|
-
|
601
|
-
@
|
600
|
+
puts "Work needed"
|
601
|
+
from_version = Gem::Version.new(@db['config']['version'])
|
602
|
+
to_version = Gem::Version.new(VERSION)
|
603
|
+
|
604
|
+
Log.warn "PostRunner version upgrade from #{from_version} to " +
|
605
|
+
"#{to_version} started."
|
606
|
+
@ffs.handle_version_update(from_version, to_version)
|
607
|
+
|
602
608
|
@db['config']['version'] = VERSION
|
603
|
-
Log.
|
609
|
+
Log.warn "PostRunner version upgrade from #{from_version} to " +
|
610
|
+
"#{to_version} completed."
|
604
611
|
end
|
605
612
|
end
|
606
613
|
|
@@ -18,6 +18,8 @@ module PostRunner
|
|
18
18
|
|
19
19
|
class UserProfileView
|
20
20
|
|
21
|
+
include Fit4Ruby::Converters
|
22
|
+
|
21
23
|
def initialize(fit_activity, unit_system)
|
22
24
|
@fit_activity = fit_activity
|
23
25
|
@unit_system = unit_system
|
@@ -44,16 +46,18 @@ module PostRunner
|
|
44
46
|
user_profile = @fit_activity.user_profiles.first
|
45
47
|
hr_zones = @fit_activity.heart_rate_zones.first
|
46
48
|
|
47
|
-
if user_data.height
|
49
|
+
if user_data && user_data.height
|
48
50
|
unit = { :metric => 'm', :statute => 'ft' }[@unit_system]
|
49
51
|
height = user_data.get_as('height', unit)
|
50
52
|
t.cell('Height:', { :width => '40%' })
|
51
53
|
t.cell("#{'%.2f' % height} #{unit}", { :width => '60%' })
|
52
54
|
t.new_row
|
53
55
|
end
|
54
|
-
if user_data.weight
|
56
|
+
if (user_data && user_data.weight) ||
|
57
|
+
(user_profile && user_profile.weight)
|
55
58
|
unit = { :metric => 'kg', :statute => 'lbs' }[@unit_system]
|
56
|
-
weight =
|
59
|
+
weight = (user_profile && user_profile.get_as('weight', unit)) ||
|
60
|
+
(user_data && user_data.get_as('weight', unit))
|
57
61
|
t.row([ 'Weight:', "#{'%.1f' % weight} #{unit}" ])
|
58
62
|
end
|
59
63
|
t.row([ 'Gender:', user_data.gender ]) if user_data.gender
|
@@ -66,15 +70,23 @@ module PostRunner
|
|
66
70
|
(max_hr = hr_zones.max_heart_rate)
|
67
71
|
t.row([ 'Max. Heart Rate:', "#{max_hr} bpm" ])
|
68
72
|
end
|
69
|
-
if (
|
70
|
-
t.row([ '
|
73
|
+
if user_profile && (date = user_profile.time_last_lthr_update)
|
74
|
+
t.row([ 'Last Lactate Threshold Update:', date ])
|
75
|
+
end
|
76
|
+
if user_data && (lthr = user_data.running_lactate_threshold_heart_rate)
|
77
|
+
t.row([ 'Running LT Heart Rate:', "#{lthr} bpm" ])
|
78
|
+
end
|
79
|
+
if user_profile && (speed = user_profile.functional_threshold_speed)
|
80
|
+
unit = { :metric => 'min/km', :statute => 'min/mile' }[@unit_system]
|
81
|
+
t.row([ 'Running LT Pace:', "#{speedToPace(speed)} #{unit}" ])
|
71
82
|
end
|
72
83
|
if (activity_class = user_data.activity_class)
|
73
84
|
t.row([ 'Activity Class:', activity_class ])
|
74
85
|
end
|
75
|
-
|
76
|
-
|
77
|
-
|
86
|
+
# It's unlikely that anybody ever cares about the METmax value.
|
87
|
+
#if (metmax = user_data.metmax)
|
88
|
+
# t.row([ 'METmax:', "#{metmax} MET" ])
|
89
|
+
#end
|
78
90
|
if (vo2max = @fit_activity.vo2max)
|
79
91
|
t.row([ 'VO2max:', "#{'%.1f' % vo2max} ml/kg/min" ])
|
80
92
|
end
|
data/lib/postrunner/version.rb
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
#
|
4
4
|
# = version.rb -- PostRunner - Manage the data from your Garmin sport devices.
|
5
5
|
#
|
6
|
-
# Copyright (c) 2014, 2015, 2016, 2017 by Chris Schlaeger <cs@taskjuggler.org>
|
6
|
+
# Copyright (c) 2014, 2015, 2016, 2017, 2020 by Chris Schlaeger <cs@taskjuggler.org>
|
7
7
|
#
|
8
8
|
# This program is free software; you can redistribute it and/or modify
|
9
9
|
# it under the terms of version 2 of the GNU General Public License as
|
@@ -11,5 +11,5 @@
|
|
11
11
|
#
|
12
12
|
|
13
13
|
module PostRunner
|
14
|
-
VERSION = '0.
|
14
|
+
VERSION = '1.0.0'
|
15
15
|
end
|
data/postrunner.gemspec
CHANGED
@@ -28,8 +28,8 @@ operating systems as well.}
|
|
28
28
|
spec.require_paths = ["lib"]
|
29
29
|
spec.required_ruby_version = '>=2.4'
|
30
30
|
|
31
|
-
spec.add_dependency 'fit4ruby', '~> 3.
|
32
|
-
spec.add_dependency 'perobs', '~> 4.
|
31
|
+
spec.add_dependency 'fit4ruby', '~> 3.6.0'
|
32
|
+
spec.add_dependency 'perobs', '~> 4.2.0'
|
33
33
|
spec.add_dependency 'nokogiri', '~> 1.6'
|
34
34
|
|
35
35
|
spec.add_development_dependency 'bundler', '~> 1.6'
|
data/spec/FitFileStore_spec.rb
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
#
|
4
4
|
# = PostRunner_spec.rb -- PostRunner - Manage the data from your Garmin sport devices.
|
5
5
|
#
|
6
|
-
# Copyright (c) 2014, 2015, 2016 by Chris Schlaeger <cs@taskjuggler.org>
|
6
|
+
# Copyright (c) 2014, 2015, 2016, 2020 by Chris Schlaeger <cs@taskjuggler.org>
|
7
7
|
#
|
8
8
|
# This program is free software; you can redistribute it and/or modify
|
9
9
|
# it under the terms of version 2 of the GNU General Public License as
|
@@ -51,7 +51,7 @@ describe PostRunner::FitFileStore do
|
|
51
51
|
expect(@activities[-1]).not_to be_nil
|
52
52
|
|
53
53
|
expect(@ffs.devices.length).to eq(1)
|
54
|
-
expect(@ffs.devices.include?('
|
54
|
+
expect(@ffs.devices.include?('1-2050-123456790')).to be true
|
55
55
|
expect(@ffs.activities.length).to eq(1)
|
56
56
|
expect(@ffs.ref_by_activity(@activities[0])).to eq(1)
|
57
57
|
end
|
@@ -60,7 +60,7 @@ describe PostRunner::FitFileStore do
|
|
60
60
|
expect(@ffs.add_fit_file(@fit_file_names[0])).to be_nil
|
61
61
|
|
62
62
|
expect(@ffs.devices.length).to eq(1)
|
63
|
-
expect(@ffs.devices.include?('
|
63
|
+
expect(@ffs.devices.include?('1-2050-123456790')).to be true
|
64
64
|
expect(@ffs.activities.length).to eq(1)
|
65
65
|
end
|
66
66
|
|
@@ -69,8 +69,8 @@ describe PostRunner::FitFileStore do
|
|
69
69
|
expect(@activities[-1]).not_to be_nil
|
70
70
|
|
71
71
|
expect(@ffs.devices.length).to eq(2)
|
72
|
-
expect(@ffs.devices.include?('
|
73
|
-
expect(@ffs.devices.include?('
|
72
|
+
expect(@ffs.devices.include?('1-2050-123456790')).to be true
|
73
|
+
expect(@ffs.devices.include?('1-2050-123456791')).to be true
|
74
74
|
expect(@ffs.activities.length).to eq(2)
|
75
75
|
expect(@ffs.ref_by_activity(@activities[1])).to eq(1)
|
76
76
|
end
|
@@ -80,8 +80,8 @@ describe PostRunner::FitFileStore do
|
|
80
80
|
expect(@activities[-1]).not_to be_nil
|
81
81
|
|
82
82
|
expect(@ffs.devices.length).to eq(2)
|
83
|
-
expect(@ffs.devices.include?('
|
84
|
-
expect(@ffs.devices.include?('
|
83
|
+
expect(@ffs.devices.include?('1-2050-123456790')).to be true
|
84
|
+
expect(@ffs.devices.include?('1-2050-123456791')).to be true
|
85
85
|
expect(@ffs.activities.length).to eq(3)
|
86
86
|
expect(@ffs.ref_by_activity(@activities[2])).to eq(1)
|
87
87
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: postrunner
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Chris Schlaeger
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-07-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: fit4ruby
|
@@ -16,28 +16,28 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 3.
|
19
|
+
version: 3.6.0
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 3.
|
26
|
+
version: 3.6.0
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: perobs
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 4.
|
33
|
+
version: 4.2.0
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: 4.
|
40
|
+
version: 4.2.0
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: nokogiri
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -342,7 +342,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
342
342
|
version: '0'
|
343
343
|
requirements: []
|
344
344
|
rubyforge_project:
|
345
|
-
rubygems_version: 2.2
|
345
|
+
rubygems_version: 2.7.6.2
|
346
346
|
signing_key:
|
347
347
|
specification_version: 4
|
348
348
|
summary: Application to manage and analyze Garmin FIT files.
|