summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorChris Schlaeger <chris@linux.com>2016-05-16 22:20:00 +0200
committerChris Schlaeger <chris@linux.com>2016-05-16 22:20:00 +0200
commit49634d7c5125440ad771850e210208869390ef75 (patch)
tree5e3a7dfd6f7420f8d6263068488896d247e3aa5c /lib
parentb1524ddb6364dee2e5b2dee9f7586e3aa8d1e115 (diff)
downloadpostrunner-49634d7c5125440ad771850e210208869390ef75.zip
New: Daily and monthly reports for monitoring data
Diffstat (limited to 'lib')
-rw-r--r--lib/postrunner/FitFileStore.rb6
-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