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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 351aade063aa03b50f3563a29ff77549c336970b
4
- data.tar.gz: 9850c9ea5c0a0b59697423a7a70851d7292647ec
2
+ SHA256:
3
+ metadata.gz: bb8a80028ee50a8f543d589b44fd41523208483a1743d29ec86e37525ff84a13
4
+ data.tar.gz: 9834c6dc556e9e118fca144a8edd33e9cecc51eb9bc4487d43218973f5dae719
5
5
  SHA512:
6
- metadata.gz: b55b1de8af615a5213e5b9a185d8b3c4e93219a64ea2fefbd394ebd6e4a3e1c83a5ea39c28d76cc4d9528409ea0ba754d718418e413f8f23170bff620f40ba88
7
- data.tar.gz: fdb2911f5ef016648f9d426a98de321ad5e46387ed6500348d86bdd34a00bb49900dae6012dab25611fca08fdcdfa5c3aea15368d77e34bf9a00cd51eadec690
6
+ metadata.gz: 8544b0aca1e86a9ca4e90aa437684a9fc56ac925cefe115ac9453816d1373242fcf6aa94d86ea779ea947ebb982b318141c45df43197d77a78b2375aeb5f6724
7
+ data.tar.gz: d5354f1f321685cb7181c75cee537d36695bddb0cecea175cd703de678af9055db10e089740f6719f1c6097e3fc2a2713951ae396b558b3ffc39a5bbfbe9f722
@@ -380,7 +380,7 @@ module PostRunner
380
380
  end
381
381
 
382
382
  def activity_sub_type
383
- ActivitySubTypes[@sub_sport] || 'Undefined "#{@sub_sport}"'
383
+ ActivitySubTypes[@sub_sport] || "Undefined #{@sub_sport}"
384
384
  end
385
385
 
386
386
  def distance(timestamp, unit_system)
@@ -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' : ''}"
@@ -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',
@@ -253,7 +253,7 @@ module PostRunner
253
253
  end
254
254
 
255
255
  def activity_sub_type
256
- ActivitySubTypes[@sub_sport] || 'Undefined'
256
+ ActivitySubTypes[@sub_sport] || "Undefined #{@sub_sport}"
257
257
  end
258
258
 
259
259
  def distance(timestamp, unit_system)
@@ -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 true.
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 an Array in the store to hold all known devices.
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
- # Nothing here so far.
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[:manufacturer]}-#{id[:product]}-#{id[:serial_number]}"
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), 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]
@@ -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
- Log.warn "PostRunner version upgrade detected."
601
- @ffs.handle_version_update
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.info "Version upgrade completed."
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 = user_data.get_as('weight', unit)
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 (lthr = user_data.running_lactate_threshold_heart_rate)
70
- t.row([ 'Running LTHR:', "#{lthr} bpm" ])
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
- if (metmax = user_data.metmax)
76
- t.row([ 'METmax:', "#{metmax} MET" ])
77
- end
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
@@ -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.12.0'
14
+ VERSION = '1.0.0'
15
15
  end
@@ -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.3.0'
32
- spec.add_dependency 'perobs', '~> 4.1.0'
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'
@@ -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?('garmin-fenix3-123456790')).to be true
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?('garmin-fenix3-123456790')).to be true
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?('garmin-fenix3-123456790')).to be true
73
- expect(@ffs.devices.include?('garmin-fenix3-123456791')).to be true
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?('garmin-fenix3-123456790')).to be true
84
- expect(@ffs.devices.include?('garmin-fenix3-123456791')).to be true
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.12.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: 2019-09-03 00:00:00.000000000 Z
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.3.0
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.3.0
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.1.0
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.1.0
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.5
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.