diff options
author | Chris Schlaeger <chris@linux.com> | 2016-05-16 22:20:00 +0200 |
---|---|---|
committer | Chris Schlaeger <chris@linux.com> | 2016-05-16 22:20:00 +0200 |
commit | 49634d7c5125440ad771850e210208869390ef75 (patch) | |
tree | 5e3a7dfd6f7420f8d6263068488896d247e3aa5c | |
parent | b1524ddb6364dee2e5b2dee9f7586e3aa8d1e115 (diff) | |
download | postrunner-49634d7c5125440ad771850e210208869390ef75.zip |
New: Daily and monthly reports for monitoring data
-rw-r--r-- | lib/postrunner/FitFileStore.rb | 6 | ||||
-rw-r--r-- | lib/postrunner/MonitoringStatistics.rb (renamed from lib/postrunner/SleepStatistics.rb) | 258 |
2 files changed, 184 insertions, 80 deletions
diff --git a/lib/postrunner/FitFileStore.rb b/lib/postrunner/FitFileStore.rb index d7933e1..2be40c4 100644 --- a/lib/postrunner/FitFileStore.rb +++ b/lib/postrunner/FitFileStore.rb @@ -18,7 +18,7 @@ require 'postrunner/DirUtils' require 'postrunner/FFS_Device' require 'postrunner/ActivityListView' require 'postrunner/ViewButtons' -require 'postrunner/SleepStatistics' +require 'postrunner/MonitoringStatistics' module PostRunner @@ -338,7 +338,7 @@ module PostRunner read_fit_file(File.join(fit_file_dir(m.fit_file_name, m.device.long_uid, 'monitor'), m.fit_file_name)) end - puts SleepStatistics.new(monitoring_files).daily(day) + puts MonitoringStatistics.new(monitoring_files).daily(day) end def monthly_report(day) @@ -361,7 +361,7 @@ module PostRunner read_fit_file(File.join(fit_file_dir(m.fit_file_name, m.device.long_uid, 'monitor'), m.fit_file_name)) end - puts SleepStatistics.new(monitoring_files).monthly(day) + puts MonitoringStatistics.new(monitoring_files).monthly(day) end private diff --git a/lib/postrunner/SleepStatistics.rb b/lib/postrunner/MonitoringStatistics.rb index ca35286..c6d2da1 100644 --- a/lib/postrunner/SleepStatistics.rb +++ b/lib/postrunner/MonitoringStatistics.rb @@ -1,7 +1,7 @@ #!/usr/bin/env ruby -w # encoding: UTF-8 # -# = SleepStatistics.rb -- PostRunner - Manage the data from your Garmin sport devices. +# = MonitoringStatistics.rb -- PostRunner - Manage the data from your Garmin sport devices. # # Copyright (c) 2016 by Chris Schlaeger <cs@taskjuggler.org> # @@ -13,6 +13,7 @@ require 'fit4ruby' require 'postrunner/DailySleepAnalyzer' +require 'postrunner/DailyMonitoringAnalyzer' require 'postrunner/FlexiTable' module PostRunner @@ -20,11 +21,11 @@ module PostRunner # This class can be used to generate reports for sleep data. It uses the # DailySleepAnalyzer class to compute the data and generates the report for # a certain time period. - class SleepStatistics + class MonitoringStatistics include Fit4Ruby::Converters - # Create a new SleepStatistics object. + # Create a new MonitoringStatistics object. # @param monitoring_files [Array of Fit4Ruby::Monitoring_B] FIT files def initialize(monitoring_files) @monitoring_files = monitoring_files @@ -33,15 +34,36 @@ module PostRunner # Generate a report for a certain day. # @param day [String] Date of the day as YYYY-MM-DD string. def daily(day) - analyzer = DailySleepAnalyzer.new(@monitoring_files, day, -12 * 60 * 60) + sleep_analyzer = DailySleepAnalyzer.new(@monitoring_files, day, + -12 * 60 * 60) + monitoring_analyzer = DailyMonitoringAnalyzer.new(@monitoring_files, day) - if analyzer.sleep_cycles.empty? - return 'No sleep data available for this day' + str = '' + if sleep_analyzer.sleep_cycles.empty? + str += 'No sleep data available for this day' + else + str += "Sleep Statistics for #{day}\n\n" + + daily_sleep_cycle_table(sleep_analyzer).to_s + + "\nResting heart rate: #{sleep_analyzer.resting_heart_rate} BPM\n" end - - "Sleep Statistics for #{day}\n\n" + - daily_sleep_cycle_table(analyzer).to_s + - "\nResting heart rate: #{analyzer.resting_heart_rate} BPM" + steps_distance_calories = monitoring_analyzer.steps_distance_calories + steps = steps_distance_calories[:steps] + steps_goal = monitoring_analyzer.steps_goal + str += "Steps: #{steps} " + + "(#{percent(steps, steps_goal)} of daily goal #{steps_goal})\n" + intensity_minutes = + monitoring_analyzer.intensity_minutes[:moderate_minutes] + + 2 * monitoring_analyzer.intensity_minutes[:vigorous_minutes] + str += "Intensity Minutes: #{intensity_minutes} " + + "(#{percent(intensity_minutes, 150)} of weekly goal 150)\n" + floors = monitoring_analyzer.total_floors + floors_climbed = floors[:floors_climbed] + str += "Floors climbed: #{floors_climbed} " + + "(#{percent(floors_climbed, 10)} of daily goal 10)\n" + + "Floors descended: #{floors[:floors_descended]}\n" + str += "Distance: " + + "#{'%.1f' % (steps_distance_calories[:distance] / 1000.0)} km\n" + str += "Calories: #{steps_distance_calories[:calories].to_i}\n" end # Generate a report for a certain month. @@ -52,77 +74,17 @@ module PostRunner month = day_as_time.month last_day_of_month = Date.new(year, month, -1).day - t = FlexiTable.new - left = { :halign => :left } - right = { :halign => :right } - t.set_column_attributes( - [ left, right, right, right, right, right, right ]) - t.head - t.row([ 'Date', 'Total Sleep', 'Cycles', 'REM Sleep', 'Light Sleep', - 'Deep Sleep', 'RHR' ]) - t.body - totals = Hash.new(0) - counted_days = 0 - rhr_days = 0 - - 1.upto(last_day_of_month).each do |dom| - break if (time = Time.new(year, month, dom)) > Time.now - - day_str = time.strftime('%Y-%m-%d') - t.cell(day_str) - - analyzer = DailySleepAnalyzer.new(@monitoring_files, day_str, - -12 * 60 * 60) - - if (analyzer.sleep_cycles.empty?) - 5.times { t.cell('-') } - else - totals[:total_sleep] += analyzer.total_sleep - totals[:cycles] += analyzer.sleep_cycles.length - totals[:rem_sleep] += analyzer.rem_sleep - totals[:light_sleep] += analyzer.light_sleep - totals[:deep_sleep] += analyzer.deep_sleep - counted_days += 1 - - t.cell(secsToHM(analyzer.total_sleep)) - t.cell(analyzer.sleep_cycles.length) - t.cell(secsToHM(analyzer.rem_sleep)) - t.cell(secsToHM(analyzer.light_sleep)) - t.cell(secsToHM(analyzer.deep_sleep)) - end - - if (rhr = analyzer.resting_heart_rate) && rhr > 0 - t.cell(rhr) - totals[:rhr] += rhr - rhr_days += 1 - else - t.cell('-') - end - t.new_row - end - t.foot - t.cell('Averages') - if counted_days > 0 - t.cell(secsToHM(totals[:total_sleep] / counted_days)) - t.cell('%.1f' % (totals[:cycles] / counted_days)) - t.cell(secsToHM(totals[:rem_sleep] / counted_days)) - t.cell(secsToHM(totals[:light_sleep] / counted_days)) - t.cell(secsToHM(totals[:deep_sleep] / counted_days)) - else - 5.times { t.cell('-') } - end - if rhr_days > 0 - t.cell('%.1f' % (totals[:rhr] / rhr_days)) - else - t.cell('-') - end - t.new_row - - "Sleep Statistics for #{day_as_time.strftime('%B')} #{year}\n\n#{t}" + "Monitoring Statistics for #{day_as_time.strftime('%B %Y')}\n\n" + + monthly_goal_table(year, month, last_day_of_month).to_s + "\n" + + monthly_sleep_table(year, month, last_day_of_month).to_s end private + def percent(value, total) + "#{'%.0f' % ((value * 100.0) / total)}%" + end + def cell_right_aligned(table, text) table.cell(text, { :halign => :right }) end @@ -190,6 +152,148 @@ module PostRunner ti end + def monthly_goal_table(year, month, last_day_of_month) + t = FlexiTable.new + left = { :halign => :left } + right = { :halign => :right } + t.set_column_attributes([ left ] + [ right ] * 7) + t.head + t.row([ 'Date', 'Steps', '%', 'Goal', 'Intensity', '%', + 'Floors', '% of 10' ]) + t.row([ '', '', '', '', 'Minutes', 'Week', '', '' ]) + t.body + totals = Hash.new(0) + counted_days = 0 + weekly_intensity_minutes = 0 + 1.upto(last_day_of_month).each do |dom| + break if (time = Time.new(year, month, dom)) > Time.now + + day_str = time.strftime('%Y-%m-%d') + t.cell(day_str) + + analyzer = DailyMonitoringAnalyzer.new(@monitoring_files, day_str) + + steps_distance_calories = analyzer.steps_distance_calories + steps = steps_distance_calories[:steps] + totals[:steps] += steps + steps_goal = analyzer.steps_goal + totals[:steps_goal] += steps_goal + t.cell(steps) + t.cell(percent(steps, steps_goal)) + t.cell(steps_goal) + + weekly_intensity_minutes = 0 if time.wday == 1 + intensity_minutes = + analyzer.intensity_minutes[:moderate_minutes] + + 2 * analyzer.intensity_minutes[:vigorous_minutes] + weekly_intensity_minutes += intensity_minutes + totals[:intensity_minutes] += intensity_minutes + t.cell(weekly_intensity_minutes.to_i) + t.cell(percent(weekly_intensity_minutes, 150)) + + floors = analyzer.total_floors + floors_climbed = floors[:floors_climbed] + totals[:floors] += floors_climbed + t.cell(floors_climbed) + t.cell(percent(floors_climbed, 10)) + t.new_row + counted_days += 1 + end + + t.foot + t.cell('Totals') + t.cell(totals[:steps]) + t.cell('') + t.cell(totals[:steps_goal]) + t.cell(totals[:intensity_minutes].to_i) + t.cell('') + t.cell(totals[:floors]) + t.cell('') + t.new_row + + if counted_days > 0 + t.cell('Averages') + t.cell((totals[:steps] / counted_days).to_i) + t.cell(percent(totals[:steps], totals[:steps_goal])) + t.cell((totals[:steps_goal] / counted_days).to_i) + t.cell((totals[:intensity_minutes] / counted_days).to_i) + t.cell(percent(totals[:intensity_minutes], (counted_days / 7.0) * 150)) + t.cell((totals[:floors] / counted_days).to_i) + t.cell(percent(totals[:floors] / counted_days, 10)) + end + + t + end + + def monthly_sleep_table(year, month, last_day_of_month) + t = FlexiTable.new + left = { :halign => :left } + right = { :halign => :right } + t.set_column_attributes([ left ] + [ right ] * 6) + t.head + t.row([ 'Date', 'Total Sleep', 'Cycles', 'REM Sleep', 'Light Sleep', + 'Deep Sleep', 'RHR' ]) + t.body + totals = Hash.new(0) + counted_days = 0 + rhr_days = 0 + + 1.upto(last_day_of_month).each do |dom| + break if (time = Time.new(year, month, dom)) > Time.now + + day_str = time.strftime('%Y-%m-%d') + t.cell(day_str) + + analyzer = DailySleepAnalyzer.new(@monitoring_files, day_str, + -12 * 60 * 60) + + if (analyzer.sleep_cycles.empty?) + 5.times { t.cell('-') } + else + totals[:total_sleep] += analyzer.total_sleep + totals[:cycles] += analyzer.sleep_cycles.length + totals[:rem_sleep] += analyzer.rem_sleep + totals[:light_sleep] += analyzer.light_sleep + totals[:deep_sleep] += analyzer.deep_sleep + counted_days += 1 + + t.cell(secsToHM(analyzer.total_sleep)) + t.cell(analyzer.sleep_cycles.length) + t.cell(secsToHM(analyzer.rem_sleep)) + t.cell(secsToHM(analyzer.light_sleep)) + t.cell(secsToHM(analyzer.deep_sleep)) + end + + if (rhr = analyzer.resting_heart_rate) && rhr > 0 + t.cell(rhr) + totals[:rhr] += rhr + rhr_days += 1 + else + t.cell('-') + end + t.new_row + end + t.foot + t.cell('Averages') + if counted_days > 0 + t.cell(secsToHM(totals[:total_sleep] / counted_days)) + t.cell('%.1f' % (totals[:cycles] / counted_days)) + t.cell(secsToHM(totals[:rem_sleep] / counted_days)) + t.cell(secsToHM(totals[:light_sleep] / counted_days)) + t.cell(secsToHM(totals[:deep_sleep] / counted_days)) + else + 5.times { t.cell('-') } + end + if rhr_days > 0 + t.cell('%.0f' % (totals[:rhr] / rhr_days)) + else + t.cell('-') + end + t.new_row + + t + end + end end |