further implementation of fitbit

This commit is contained in:
Bastian Greshake
2012-09-06 21:07:50 +02:00
parent dc12204ff1
commit 50f9efecbe
17 changed files with 202 additions and 28 deletions

View File

@@ -1,6 +1,6 @@
class FitbitProfilesController < ApplicationController
before_filter :require_user, except: [:new_notification]
before_filter :require_owner, only: [:update]
before_filter :require_user, only: [:update,:destroy,:init,:edit,:start_auth,:verify_auth,:dump]
protect_from_forgery :except => :new_notification
@@ -12,6 +12,14 @@ class FitbitProfilesController < ApplicationController
end
end
def dump
@fitbit_profile = FitbitProfile.find_by_id(params[:id]) || not_found
Resque.enqueue(FitbitDump,current_user.email,@fitbit_profile.id)
respond_to do |format|
format.html
end
end
def info
respond_to do |format|
format.html
@@ -24,6 +32,14 @@ class FitbitProfilesController < ApplicationController
format.html
end
end
def destroy
@fitbit_profile = current_user.fitbit_profile
Resque.enqueue(FitbitEndSubscription,@fitbit_profile.id)
respond_to do |format|
format.html
end
end
def init
@user = current_user

60
app/jobs/fitbit_dump.rb Normal file
View File

@@ -0,0 +1,60 @@
require 'resque'
class FitbitDump
@queue = :fitbitdump
def self.perform(target_address,fitbit_profile_id)
fp = FitbitProfile.find_by_id(fitbit_profile_id)
# open handle
@time = Time.now.utc
@time_str = @time.strftime("%Y%m%d%H%M")
@time = @time.to_s.gsub(":","_")
@fitbit_handle = File.new(::Rails.root.to_s+"/public/data/fitbit/user"+fp.user.id.to_s+"_fitbit_data_"+@time_str.to_s+".csv","w")
@fitbit_handle.puts("date;steps;floors;weight;bmi;minutes asleep;minutes awake; times awaken; minutes until fell asleep")
# get all dates which have to be included in the csv
@time_array = []
fp.fitbit_bodies.each do |fb|
@time_array << fb.date_logged
end
fp.fitbit_sleeps.each do |fs|
@time_array << fs.date_logged
end
fp.fitbit_activities.each do |fa|
@time_array << fa.date_logged
end
@time_array = @time_array.uniq.sort
@time_array.each do |d|
@line = d + ";"
@activity = fp.fitbit_activities.find_by_date_logged(d)
if @activity == nil
@line = @line + "-;-;"
else
@line = @line + @activity.steps + ";" + @activity.floors+ ";"
end
@body = fp.fitbit_bodies.find_by_date_logged(d)
if @body == nil
@line = @line + "-;-;"
else
@line = @line + @body.weight + ";" + @body.bmi + ";"
end
@sleep = fp.fitbit_sleeps.find_by_date_logged(d)
if @sleep == nil
@line = @line + "-;-;-;-;"
else
@line = @line + @sleep.minutes_asleep+";"+@sleep.minutes_awake+";"+@sleep.number_awakenings+";"+@sleep.minutes_to_sleep+";"
end
@fitbit_handle.puts(@line)
end
@fitbit_handle.close
puts "Saved fibit-date for "
system("chmod 777 "+::Rails.root.to_s+"/public/data/fitbit/user"+fp.user.id.to_s+"_fitbit_data_"+@time_str.to_s+".csv")
UserMailer.fitbit_dump(target_address,"/data/fitbit/user"+fp.user.id.to_s+"_fitbit_data_"+@time_str.to_s+".csv").deliver
end
end

View File

@@ -7,13 +7,12 @@ class FitbitEdit
@fitbit_profile = FitbitProfile.find_by_id(fitbit_profile_id)
@client = Fitgem::Client.new(:consumer_key => APP_CONFIG[:fitbit_consumer_key], :consumer_secret => APP_CONFIG[:fitbit_consumer_secret])
@client.reconnect(@fitbit_profile.access_token, @fitbit_profile.access_secret)
@client.create_subscription({:type => :all, :subscription_id => @fitbit_profile.id})
# check for body data & subscriptions
###############################################
## TODO!!!111 ##
## SET UP SUBSCRIPTION API ON THIS POINT!!!1 ##
###############################################
@return_value = @client.create_subscription({:type => :all, :subscription_id => @fitbit_profile.id})
puts "subscription returned: "+ @return_value[0]
if @return_value[0] == "409"
@client.remove_subscription({:type => :all, :subscriber_id => "general",:subscription_id => @return_value[1]["subscriptionId"]})
@client.create_subscription({:type => :all, :subscription_id => @fitbit_profile.id})
end
if @fitbit_profile.body == false
@entries = FitbitBody.find_all_by_fitbit_profile_id(@fitbit_profile.id)
@@ -27,14 +26,12 @@ class FitbitEdit
@body = FitbitBody.find_or_create_by_fitbit_profile_id_and_date_logged(@fitbit_profile.id,bmi["dateTime"])
@body.bmi = bmi["value"]
@body.save
puts "saved bmi"
end
@weight_array = @client.data_by_time_range("/body/weight",{:base_date => Date.today.to_s,:period => :max})["body-weight"]
@weight_array.each do |weight|
@body = FitbitBody.find_or_create_by_fitbit_profile_id_and_date_logged(@fitbit_profile.id,weight["dateTime"])
@body.weight = weight["value"]
@body.save
puts "saved weight"
end
end
@@ -51,28 +48,24 @@ class FitbitEdit
@sleep = FitbitSleep.find_or_create_by_fitbit_profile_id_and_date_logged(@fitbit_profile.id,m_asleep["dateTime"])
@sleep.minutes_asleep = m_asleep["value"]
@sleep.save
puts "saved minutes asleep"
end
@awakenings_array = @client.data_by_time_range("/sleep/awakeningsCount",{:base_date => Date.today.to_s,:period => :max})["sleep-awakeningsCount"]
@awakenings_array.each do |awake|
@sleep = FitbitSleep.find_or_create_by_fitbit_profile_id_and_date_logged(@fitbit_profile.id,awake["dateTime"])
@sleep.number_awakenings = awake["value"]
@sleep.save
puts "saved times awake"
end
@minutes_awake_array = @client.data_by_time_range("/sleep/minutesAwake",{:base_date => Date.today.to_s,:period => :max})["sleep-minutesAwake"]
@minutes_awake_array.each do |m_awake|
@sleep = FitbitSleep.find_or_create_by_fitbit_profile_id_and_date_logged(@fitbit_profile.id,m_awake["dateTime"])
@sleep.minutes_awake = m_awake["value"]
@sleep.save
puts "saved minutes awake"
end
@minutes_to_sleep_array = @client.data_by_time_range("/sleep/minutesToFallAsleep",{:base_date => Date.today.to_s,:period => :max})["sleep-minutesToFallAsleep"]
@minutes_to_sleep_array.each do |m|
@sleep = FitbitSleep.find_or_create_by_fitbit_profile_id_and_date_logged(@fitbit_profile.id,m["dateTime"])
@sleep.minutes_to_sleep = m["value"]
@sleep.save
puts "saved minutes to sleep"
end
end
@@ -88,14 +81,12 @@ class FitbitEdit
@activity = FitbitActivity.find_or_create_by_fitbit_profile_id_and_date_logged(@fitbit_profile.id,s["dateTime"])
@activity.steps = s["value"]
@activity.save
puts "saved steps"
end
@floors_array = @client.data_by_time_range("/activities/log/floors",{:base_date => Date.today.to_s,:period => :max})["activities-log-floors"]
@floors_array.each do |f|
@activity = FitbitActivity.find_or_create_by_fitbit_profile_id_and_date_logged(@fitbit_profile.id,f["dateTime"])
@activity.floors = f["value"]
@activity.save
puts "saved floors"
end
# grab data
end

View File

@@ -0,0 +1,13 @@
require 'resque'
class FitbitEndSubscription
@queue = :fitbitendsubscription
def self.perform(fitbit_profile_id)
@fitbit_profile = FitbitProfile.find_by_id(fitbit_profile_id)
@client = Fitgem::Client.new(:consumer_key => APP_CONFIG[:fitbit_consumer_key], :consumer_secret => APP_CONFIG[:fitbit_consumer_secret])
@client.reconnect(@fitbit_profile.access_token, @fitbit_profile.access_secret)
@client.remove_subscription({:type => :all, :subscriber_id => "general", :subscription_id => @fitbit_profile.id})
@fitbit_profile.destroy()
end
end

View File

@@ -10,6 +10,8 @@ class FitbitNotification
if @fitbit_profile != nil
@client = Fitgem::Client.new(:consumer_key => APP_CONFIG[:fitbit_consumer_key], :consumer_secret => APP_CONFIG[:fitbit_consumer_secret])
@client.reconnect(@fitbit_profile.access_token, @fitbit_profile.access_secret)
puts n
puts n["collectionType"]
if n["collectionType"] == "activities" and @fitbit_profile.activities == true
@activity = FitbitActivity.find_or_create_by_fitbit_profile_id_and_date_logged(@fitbit_profile.id,n["date"])
@steps = @client.data_by_time_range("/activities/log/steps",{:base_date => n["date"],:period => "1d"})["activities-log-steps"][0]["value"]

View File

@@ -51,7 +51,57 @@ class Zipfulldata
@csv_handle.close
puts "created csv-file"
# Create a file of fitbit-data for each user with fitbit-data
@fitbit_profiles = FitbitProfile.find(:all)
@fitbit_profiles.each do |fp|
# open handle
@fitbit_handle = File.new(::Rails.root.to_s+"/tmp/dump_user"+fp.user.id.to_s+"_fitbit_data_"+@time_str.to_s+".csv","w")
@fitbit_handle.puts("date;steps;floors;weight;bmi;minutes asleep;minutes awake; times awaken; minutes until fell asleep")
# get all dates which have to be included in the csv
@time_array = []
fp.fitbit_bodies.each do |fb|
@time_array << fb.date_logged
end
fp.fitbit_sleeps.each do |fs|
@time_array << fs.date_logged
end
fp.fitbit_activities.each do |fa|
@time_array << fa.date_logged
end
@time_array = @time_array.uniq.sort
@time_array.each do |d|
@line = d + ";"
@activity = fp.fitbit_activities.find_by_date_logged(d)
if @activity == nil
@line = @line + "-;-;"
else
@line = @line + @activity.steps + ";" + @activity.floors+ ";"
end
@body = fp.fitbit_bodies.find_by_date_logged(d)
if @body == nil
@line = @line + "-;-;"
else
@line = @line + @body.weight + ";" + @body.bmi + ";"
end
@sleep = fp.fitbit_sleeps.find_by_date_logged(d)
if @sleep == nil
@line = @line + "-;-;-;-;"
else
@line = @line + @sleep.minutes_asleep+";"+@sleep.minutes_awake+";"+@sleep.number_awakenings+";"+@sleep.minutes_to_sleep+";"
end
@fitbit_handle.puts(@line)
end
@fitbit_handle.close
puts "Saved fibit-date for "
end
# make a README containing time of zip - this way, users can compare with page-status
# and see how old the data is
@readme_handle = File.new(::Rails.root.to_s+"/tmp/dump"+@time_str.to_s+".txt","w")
@@ -78,6 +128,11 @@ class Zipfulldata
end
zipfile.add("user"+gen_file.user_id.to_s+"_file"+gen_file.id.to_s+"_yearofbirth_"+@yob+"_sex_"+@sex+"."+gen_file.filetype+".txt", ::Rails.root.to_s+"/public/data/"+ gen_file.fs_filename)
end
@fitbit_profiles.each do |fp|
zipfile.add("user"+fp.user.id.to_s+"_fitbit_data_"+@time_str.to_s+".csv",::Rails.root.to_s+"/tmp/dump_user"+fp.user.id.to_s+"_fitbit_data_"+@time_str.to_s+".csv")
end
end
if FileLink.find_by_description("all genotypes and phenotypes archive") == nil
@filelink = FileLink.new(:description => "all genotypes and phenotypes archive", :url => @zipname)
@@ -88,6 +143,9 @@ class Zipfulldata
File.delete(::Rails.root.to_s+"/tmp/dump"+@time_str.to_s+".csv")
File.delete(::Rails.root.to_s+"/tmp/dump"+@time_str.to_s+".txt")
@fitbit_profiles.each do |fp|
File.delete(::Rails.root.to_s+"/tmp/dump_user"+fp.user.id.to_s+"_fitbit_data_"+@time_str.to_s+".csv")
end
puts "created zip-file"
end

View File

@@ -67,4 +67,10 @@ default :from => "donotreply@opensnp.org"
mail(:subject => "openSNP.org: Sorry, there is no data to be dumped.", :to => target_address)
end
def fitbit_dump(target_address,link)
@link = link
mail(:subject => "openSNP.org: The Fitbit-data you requested is now ready for download",:to => target_address)
puts "http://"+ActionMailer::Base.default_url_options[:host]+@link
end
end

View File

@@ -1,6 +1,6 @@
class FitbitProfile < ActiveRecord::Base
belongs_to :user
has_many :fitbit_bodies
has_many :fitbit_activities
has_many :fitbit_sleeps
has_many :fitbit_bodies, dependent: :destroy
has_many :fitbit_activities, dependent: :destroy
has_many :fitbit_sleeps, dependent: :destroy
end

View File

@@ -1,4 +1,4 @@
<h1>FitBit Settings</h1>
<h1><em>Fitbit</em> Settings</h1>
<div class="row">
<div class="span6">
@@ -13,14 +13,21 @@
<div class="alert alert-info">
If you decide to uncheck some of the categories all data that has been saved so far will get deleted.
</div>
<%= f.submit "Save FitBit-Settings", {:class=>"btn btn-info"}%>
<%= f.submit "Save Fitbit-Settings", {:class=>"btn btn-info"}%>
<% end %>
<div class="alert alert-warning">
If you remove your <em>Fitbit</em>-account we will stop to grab new data and remove all the data that was already saved.
</div>
<%=link_to("Remove Fitbit-account",{:controller => "fitbit_profiles", :action => "destroy"},:class => "btn btn-danger")%>
</div>
<div class="span6">
<p>We will save data from three different categories: <strong>Body</strong>, <strong>Activities</strong> and <strong>Sleep</strong>.</p>
<p>For the <strong>Body</strong> category we will save your Body Mass Index (BMI) and your weight (Unfortunately there's currently no option to get your height through FitBit).</p>
<p>For the <strong>Body</strong> category we will save your Body Mass Index (BMI) and your weight (Unfortunately there's currently no option to get your height through <em>Fitbit</em>).</p>
<p>For <strong>Sleep</strong> we will save how long you have slept and how often you have awoke, how long you've been awake and how long it took you to fall asleep.</p>
<p>For the <strong>Activities</strong> we will save how many steps you have taken and how many floors you have climbed.</p><p>We will try to save the data you have uploaded to <em>FitBit</em> up to now as well. You can decide which categories we should save. So if you feel comfortable to share your activities but neither weight nor sleep information that's no problem.</p>
<p>For the <strong>Activities</strong> we will save how many steps you have taken and how many floors you have climbed.</p><p>We will try to save the data you have uploaded to <em>Fitbit</em> up to now as well. You can decide which categories we should save. So if you feel comfortable to share your activities but neither weight nor sleep information that's no problem.</p>
</div>

View File

@@ -0,0 +1,3 @@
<legend>Deleted your <em>Fitbit</em>-connection</legend>
<p class="lead">Your <em>Fitbit</em>-account has been unlinked from openSNP. All <em>Fitbit</em>-data which we had savedhas been deleted and we will not get any more updates, as long as you don't <%=link_to("reconnect your Fitbit account with openSNP",{:controller => "fitbit_profiles", :action => "start_auth"})%>.</p>

View File

@@ -0,0 +1,2 @@
<legend>Dumping <em>Fitbit</em> data for <%=@fitbit_profile.user.name%></legend>
<p class="lead">You have requested <em>Fitbit</em> data for the user <%= link_to(@fitbit_profile.user.name, @fitbit_profile.user)%>. The data is currently prepared and you will receive an email as soon as the data is ready to be downloaded. <%=link_to("Return to the Fitbit Profile" ,{:controller => "fitbit_profiles", :action => "show", :id => @fitbit_profile.id})%>.</p>

View File

@@ -1,6 +1,6 @@
<legend>Connect your <%=image_tag("/images/fitbit_logo_dark_100px.png")%> account to openSNP</legend>
<p class="lead"><em><a href="http://www.fitbit.com">FitBit</a></em> allows you to track your activities (How many steps have you taken? How many floors have you climbed?), your sleep (How long did you sleep? How often have you awoken at night?) and your body (i.e. your weight/BMI). The data collected by your <em>FitBit</em> could be a valuable extension of the phenotypes you've already entered in openSNP.</p>
<p class="lead"><em><a href="http://www.fitbit.com">Fitbit</a></em> allows you to track your activities (How many steps have you taken? How many floors have you climbed?), your sleep (How long did you sleep? How often have you awoken at night?) and your body (i.e. your weight/BMI). The data collected by your <em>Fitbit</em> could be a valuable extension of the phenotypes you've already entered in openSNP.</p>
<p class="lead">Once you've connected your <em>FitBit</em> account to openSNP we will automatically get your latest data from FitBit. So each time you synchronize your <em>FitBit</em>-tracker the changes will also appear on openSNP.</p>
<p class="lead">Once you've connected your <em>Fitbit</em> account to openSNP we will automatically get your latest data from FitBit. So each time you synchronize your <em>Fitbit</em>-tracker the changes will also appear on openSNP.</p>
<h4><%=link_to "Connect your FitBit account with openSNP",:controller => "fitbit_profiles", :action => "start_auth"%></h4>
<h4><%=link_to("Connect your Fitbit account with openSNP",{:controller => "fitbit_profiles", :action => "start_auth"},:class => "btn btn-info")%></h4>

View File

@@ -1,3 +1,3 @@
<p class="lead">Your <em>FitBit</em>-account has been connected to your openSNP-account. <strong>Please finish the initial setup below so we can start to save your <em>FitBit</em>-results</strong>.</p>
<p class="lead">Your <em>Fitbit</em>-account has been connected to your openSNP-account. <strong>Please finish the initial setup below so we can start to save your <em>Fitbit</em>-results</strong>.</p>
<%=render "form"%>

View File

@@ -0,0 +1,6 @@
<legend><%=image_tag("/images/fitbit-icon.png",:style => "vertical-align:middle")%> <em>Fitbit</em> profile for <%= link_to(@fitbit_profile.user.name, @fitbit_profile.user)%></legend>
<p class="lead">Some graphs go here. This is FitbitProfile #<%=link_to(@fitbit_profile.id ,{:controller => "fitbit_profiles", :action => "show", :id => @fitbit_profile.id})%> for user <%= link_to(@fitbit_profile.user.name, @fitbit_profile.user)%>.</p>
<%if current_user%>
<p class="lead"><%=link_to(image_tag("/images/filedownload_small.png",:style => "vertical-align:middle"),{:controller => "fitbit_profiles", :action => "dump", :id => @fitbit_profile.id})%> <%=link_to("Download a dump of the data",{:controller => "fitbit_profiles", :action => "dump", :id => @fitbit_profile.id})%></p>
<%end%>

View File

@@ -0,0 +1,7 @@
Hi,
the Fitbit data you requested for download from openSNP is now available as a CSV (Comma-separated value) file. To download them just visit:
<%="http://"+ActionMailer::Base.default_url_options[:host]+@link%>
Cheers,
your openSNP-team.

View File

@@ -29,6 +29,9 @@ Snpr::Application.routes.draw do
match '/fitbit/edit', :to => 'fitbit_profiles#edit'
match '/fitbit/init', :to => 'fitbit_profiles#init'
match '/fitbit/update/', :to => 'fitbit_profiles#update'
match '/fitbit/delete/', :to => 'fitbit_profiles#destroy'
match '/fitbit/show/:id', :to => 'fitbit_profiles#show', :as => :fitbit_show
match '/fitbit/dump/:id', :to => 'fitbit_profiles#dump', :as => :fitbit_dump
match '/users/:id/changepassword', :to => 'users#changepassword'
match '/signup', :to => 'users#new'
match '/signin', :to => 'user_sessions#new', :as => :login

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB