basis-band 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +31 -0
- data/bin/basis-band +44 -0
- data/lib/basis-band.rb +13 -0
- data/lib/basis-band/api-fetch.rb +47 -0
- data/lib/basis-band/api-response-model.rb +30 -0
- data/lib/basis-band/version.rb +3 -0
- data/test/test_api-fetch.rb +32 -0
- data/test/test_api-response-model.rb +17 -0
- metadata +73 -0
data/README.md
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Basis API Access Gem
|
|
2
|
+
|
|
3
|
+
This is extremely alpha quality, based on the existing PHP example at
|
|
4
|
+
[https://github.com/btroia/basis-data-export](https://github.com/btroia/basis-data-export).
|
|
5
|
+
That example includes instructions for finding your userid.
|
|
6
|
+
|
|
7
|
+
The command line tool here does just a one-day dump of the JSON data raw. Pass
|
|
8
|
+
it your userid and a date, and it'll spit back the raw data on stdout. For
|
|
9
|
+
instance to dump my data for Oct 14th, 2013 (of course, xxxxx represents my
|
|
10
|
+
userid, but I'm not posting that):
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
> miker $ basis-band xxxxxxxxxxxxxxxxxxxxxxxx 2013-10-14
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Or if you want to pretty print and paginate:
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
> miker $ basis-band xxxxxxxxxxxxxxxxxxxxxxxx 2013-10-14 | python -mjson.tool | more
|
|
20
|
+
{
|
|
21
|
+
"bodystates": [
|
|
22
|
+
[
|
|
23
|
+
1381816740,
|
|
24
|
+
1381842000,
|
|
25
|
+
"sleep"
|
|
26
|
+
...
|
|
27
|
+
...
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Just pushing up what I have so far, this is really meant to be a way to export to
|
|
31
|
+
CSV eventually so I can use this data in spreadsheets. To be done.
|
data/bin/basis-band
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
require 'basis-band'
|
|
4
|
+
require 'optparse'
|
|
5
|
+
|
|
6
|
+
def samples_to_csv(samples)
|
|
7
|
+
lines = []
|
|
8
|
+
cols = samples.first.keys
|
|
9
|
+
lines << cols.join(',')
|
|
10
|
+
samples.each do |s|
|
|
11
|
+
lines << cols.map{|c| s[c]}.join(",")
|
|
12
|
+
end
|
|
13
|
+
lines
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
options = {}
|
|
17
|
+
|
|
18
|
+
OptionParser.new do |opts|
|
|
19
|
+
opts.banner = "Usage: basis-band [options]"
|
|
20
|
+
opts.on("-u", "--userid [USERID]", "User ID from mybasis.com") do |u|
|
|
21
|
+
options[:userid] = u
|
|
22
|
+
end
|
|
23
|
+
opts.on("-d", "--date [DATE]", "Date to fetch from mybasis.com") do |d|
|
|
24
|
+
options[:date] = d
|
|
25
|
+
end
|
|
26
|
+
opts.on("-c", "--[no-]csv", "Output CSV format") do |c|
|
|
27
|
+
options[:csv] = c
|
|
28
|
+
end
|
|
29
|
+
end.parse!
|
|
30
|
+
|
|
31
|
+
if options[:userid] and options[:date]
|
|
32
|
+
b = BasisBand.new(options[:userid])
|
|
33
|
+
raw = b.data_for_day(options[:date])
|
|
34
|
+
else
|
|
35
|
+
raw = $stdin.read
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
if options[:csv]
|
|
39
|
+
m = ApiResponseModel.new(raw)
|
|
40
|
+
lines = samples_to_csv(m.samples_by_minute)
|
|
41
|
+
puts lines.join("\n")
|
|
42
|
+
else
|
|
43
|
+
puts raw
|
|
44
|
+
end
|
data/lib/basis-band.rb
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
require 'uri'
|
|
2
|
+
require 'net/https'
|
|
3
|
+
|
|
4
|
+
class ApiFetch
|
|
5
|
+
@@metrics = [:heartrate, :steps, :calories, :gsr, :skin_temp, :air_temp]
|
|
6
|
+
|
|
7
|
+
def flag_value(name, bool)
|
|
8
|
+
if bool
|
|
9
|
+
"#{name}=true"
|
|
10
|
+
else
|
|
11
|
+
"#{name}=false"
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def filter_params(date, summary, body_states)
|
|
16
|
+
p = ['interval=60', 'units=s', "start_date=#{date}", 'start_offset=0', 'end_offset=0']
|
|
17
|
+
p << flag_value('summary', summary)
|
|
18
|
+
p << flag_value('bodystates', body_states)
|
|
19
|
+
p.join('&')
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def metric_params(skip)
|
|
23
|
+
@@metrics.collect { |m|
|
|
24
|
+
flag_value(m.id2name, !skip.include?(m))
|
|
25
|
+
}.join("&")
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def url(userid, date, summary, body_states, skip_metrics)
|
|
29
|
+
f = filter_params(date, summary, body_states)
|
|
30
|
+
m = metric_params(skip_metrics)
|
|
31
|
+
"https://app.mybasis.com/api/v1/chart/#{userid}.json?#{f}&#{m}"
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def https_fetch(url)
|
|
35
|
+
u = URI.parse(url)
|
|
36
|
+
http = Net::HTTP.new(u.host, u.port)
|
|
37
|
+
http.use_ssl = true
|
|
38
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
|
39
|
+
request = Net::HTTP::Get.new(u.request_uri)
|
|
40
|
+
http.request(request).body
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def get_day(userid, date, summary = true, body_states = true, skip_metrics = [])
|
|
44
|
+
res = https_fetch(url(userid, date, summary, body_states, skip_metrics))
|
|
45
|
+
res
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
require 'time'
|
|
2
|
+
require 'json'
|
|
3
|
+
|
|
4
|
+
class ApiResponseModel
|
|
5
|
+
def initialize(raw_text)
|
|
6
|
+
@json = JSON.parse(raw_text)
|
|
7
|
+
# Use the local timezone intentionally
|
|
8
|
+
@starttime = Time.at(@json['starttime'])
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def hash_for_minute(min)
|
|
12
|
+
t = @starttime + (min * 60)
|
|
13
|
+
res = {'t' => t.strftime("%Y/%m/%d %H:%M:%S")}
|
|
14
|
+
for m in @json["metrics"].keys
|
|
15
|
+
res[m] = @json["metrics"][m]["values"][min]
|
|
16
|
+
end
|
|
17
|
+
res
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def num_samples
|
|
21
|
+
m = @json["metrics"].keys.first
|
|
22
|
+
@json["metrics"][m]["values"].length
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def samples_by_minute
|
|
26
|
+
(0...num_samples).map { |x|
|
|
27
|
+
hash_for_minute(x)
|
|
28
|
+
}
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
require 'test/unit'
|
|
2
|
+
require 'basis-band'
|
|
3
|
+
|
|
4
|
+
class ApiFetchTest < Test::Unit::TestCase
|
|
5
|
+
def setup
|
|
6
|
+
@f = ApiFetch.new()
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def test_defaults_url
|
|
10
|
+
url = @f.url('123user456', '1999-12-30', true, true, [])
|
|
11
|
+
assert url.include?('start_date=1999-12-30')
|
|
12
|
+
assert url.include?('summary=true')
|
|
13
|
+
assert url.include?('bodystates=true')
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def test_filter_url
|
|
17
|
+
url = @f.url('123user456', '1999-12-30', true, false, [])
|
|
18
|
+
assert url.include?('summary=true')
|
|
19
|
+
assert url.include?('bodystates=false')
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def test_metrics_url
|
|
23
|
+
url = @f.url('123user456', '1999-12-30', true, false, [:skin_temp, :steps])
|
|
24
|
+
assert url.include?('heartrate=true')
|
|
25
|
+
assert url.include?('steps=false')
|
|
26
|
+
assert url.include?('calories=true')
|
|
27
|
+
assert url.include?('gsr=true')
|
|
28
|
+
assert url.include?('skin_temp=false')
|
|
29
|
+
assert url.include?('air_temp=true')
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
require 'test/unit'
|
|
2
|
+
require 'basis-band'
|
|
3
|
+
|
|
4
|
+
class ApiResponseModelTest < Test::Unit::TestCase
|
|
5
|
+
def test_defaults_url
|
|
6
|
+
test_fn = File.expand_path('../2013-10-01.json', __FILE__)
|
|
7
|
+
raw = File.read(test_fn)
|
|
8
|
+
m = ApiResponseModel.new(raw)
|
|
9
|
+
minutes = m.samples_by_minute
|
|
10
|
+
assert minutes.length == 1440
|
|
11
|
+
min_first = minutes.first
|
|
12
|
+
assert min_first["air_temp"] == 80.6
|
|
13
|
+
min_last = minutes.last
|
|
14
|
+
assert min_last["air_temp"] == 81.5
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
metadata
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: basis-band
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.0.0
|
|
5
|
+
prerelease:
|
|
6
|
+
platform: ruby
|
|
7
|
+
authors:
|
|
8
|
+
- Mike Rowehl
|
|
9
|
+
autorequire:
|
|
10
|
+
bindir: bin
|
|
11
|
+
cert_chain: []
|
|
12
|
+
date: 2013-10-16 00:00:00.000000000 Z
|
|
13
|
+
dependencies:
|
|
14
|
+
- !ruby/object:Gem::Dependency
|
|
15
|
+
name: json
|
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
|
17
|
+
none: false
|
|
18
|
+
requirements:
|
|
19
|
+
- - ! '>='
|
|
20
|
+
- !ruby/object:Gem::Version
|
|
21
|
+
version: '0'
|
|
22
|
+
type: :runtime
|
|
23
|
+
prerelease: false
|
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
25
|
+
none: false
|
|
26
|
+
requirements:
|
|
27
|
+
- - ! '>='
|
|
28
|
+
- !ruby/object:Gem::Version
|
|
29
|
+
version: '0'
|
|
30
|
+
description: A library and collection for tools for exporting monitoring data from
|
|
31
|
+
the website for the Basis B1 Band device. See http://mybasis.com
|
|
32
|
+
email: mikerowehl@gmail.com
|
|
33
|
+
executables:
|
|
34
|
+
- basis-band
|
|
35
|
+
extensions: []
|
|
36
|
+
extra_rdoc_files: []
|
|
37
|
+
files:
|
|
38
|
+
- lib/basis-band/api-fetch.rb
|
|
39
|
+
- lib/basis-band/api-response-model.rb
|
|
40
|
+
- lib/basis-band/version.rb
|
|
41
|
+
- lib/basis-band.rb
|
|
42
|
+
- bin/basis-band
|
|
43
|
+
- README.md
|
|
44
|
+
- test/test_api-fetch.rb
|
|
45
|
+
- test/test_api-response-model.rb
|
|
46
|
+
homepage: http://github.com/mikerowehl/basis-band
|
|
47
|
+
licenses:
|
|
48
|
+
- MIT
|
|
49
|
+
post_install_message:
|
|
50
|
+
rdoc_options: []
|
|
51
|
+
require_paths:
|
|
52
|
+
- lib
|
|
53
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
54
|
+
none: false
|
|
55
|
+
requirements:
|
|
56
|
+
- - ! '>='
|
|
57
|
+
- !ruby/object:Gem::Version
|
|
58
|
+
version: '0'
|
|
59
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
60
|
+
none: false
|
|
61
|
+
requirements:
|
|
62
|
+
- - ! '>='
|
|
63
|
+
- !ruby/object:Gem::Version
|
|
64
|
+
version: '0'
|
|
65
|
+
requirements: []
|
|
66
|
+
rubyforge_project:
|
|
67
|
+
rubygems_version: 1.8.25
|
|
68
|
+
signing_key:
|
|
69
|
+
specification_version: 3
|
|
70
|
+
summary: Provides access to data from mybasis.com
|
|
71
|
+
test_files:
|
|
72
|
+
- test/test_api-fetch.rb
|
|
73
|
+
- test/test_api-response-model.rb
|