forked from cmaion/polar
-
Notifications
You must be signed in to change notification settings - Fork 0
/
polar_activitysamples2csv
executable file
·94 lines (75 loc) · 3.43 KB
/
polar_activitysamples2csv
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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
#!/usr/bin/env ruby
# Parses RAW Polar activity samples data files (activity type, steps, metabolic equivalent, sport id and inactivity notifications through the day) and convert to CSV
require "#{File.dirname(__FILE__)}/lib/polar_data_parser"
def usage
puts "Usage:"
puts " #{__FILE__} <directory> [<csv file>]"
end
dir = ARGV[0]
unless dir
usage
exit -2
end
output_file = ARGV[1] || File.join(dir, 'output.csv')
def output_csv(parsed)
samples = parsed[:samples]
start_time = DateTime.new(samples.start_time.date.year, samples.start_time.date.month, samples.start_time.date.day, samples.start_time.time.hour, samples.start_time.time.minute, samples.start_time.time.seconds, "%+i" % (samples.start_time.time_zone_offset / 60)).to_time
result = {}
# Steps
steps_interval = samples.steps_recording_interval.hours * 3600 + samples.steps_recording_interval.minutes * 60 + samples.steps_recording_interval.seconds + samples.steps_recording_interval.millis.to_f / 1000
samples.steps_samples.each_with_index do |steps, i|
ts = start_time + i * steps_interval
result[ts] ||= {}
result[ts][:steps] = steps
end
# met (metabolic equivalent)
met_interval = samples.met_recording_interval.hours * 3600 + samples.met_recording_interval.minutes * 60 + samples.met_recording_interval.seconds + samples.met_recording_interval.millis.to_f / 1000
samples.met_samples.each_with_index do |met, i|
ts = start_time + i * met_interval
result[ts] ||= {}
result[ts][:met] = met
end
# Activity info
samples.activity_info.each do |act|
ts = DateTime.new(act.time_stamp.date.year, act.time_stamp.date.month, act.time_stamp.date.day, act.time_stamp.time.hour, act.time_stamp.time.minute, act.time_stamp.time.seconds, "%+i" % (act.time_stamp.time_zone_offset / 60)).to_time
result[ts] ||= {}
result[ts][:activity] = act.value
end
# Sport info
samples.sport_info.each do |sport|
ts = DateTime.new(sport.time_stamp.date.year, sport.time_stamp.date.month, sport.time_stamp.date.day, sport.time_stamp.time.hour, sport.time_stamp.time.minute, sport.time_stamp.time.seconds, "%+i" % (sport.time_stamp.time_zone_offset / 60)).to_time
result[ts] ||= {}
result[ts][:sport] = sport.sport_profile_id
end
# Inactivity
samples.inactivity_trigger.each do |inactivity|
ts = DateTime.new(inactivity.time_stamp.date.year, inactivity.time_stamp.date.month, inactivity.time_stamp.date.day, inactivity.time_stamp.time.hour, inactivity.time_stamp.time.minute, inactivity.time_stamp.time.seconds, "%+i" % (inactivity.time_stamp.time_zone_offset / 60)).to_time
result[ts] ||= {}
result[ts][:inactivity] = true
end
# Result
buffer = "Time,Activity,Steps,Metabolic equivalent,Sport,Inactivity notification\n"
no_sport = (1<<64)-1
sport = no_sport
activity_name = ''
result.sort { |(ts1,r1),(ts2,r2)| ts1 <=> ts2 }.each do |ts, r|
if r[:activity]
activity_name = r[:activity].to_s
end
if r[:sport]
sport = r[:sport]
end
buffer << "#{ts},#{activity_name},#{r[:steps]},#{r[:met]},#{sport == no_sport ? -1 : sport},#{r[:inactivity]}\n" if r.key?(:step) || r.key?(:met)
end
buffer
end
puts "Converting Polar daily activity samples in '#{dir}' to CSV format as '#{output_file}'..."
parsed = PolarDataParser.parse_activity_samples(dir)
if parsed.key?(:samples)
File.open(output_file, 'w') do |f|
f << output_csv(parsed)
end
puts "Done"
else
puts "Error: couldn't find activity samples"
end