hello-sense 0.1.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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +9 -0
- data/CONTRIBUTING.md +56 -0
- data/LICENSE +21 -0
- data/README.md +55 -0
- data/hello_sense.gemspec +24 -0
- data/lib/hello_sense.rb +30 -0
- data/lib/hello_sense/account.rb +130 -0
- data/lib/hello_sense/alarms.rb +59 -0
- data/lib/hello_sense/alerts.rb +14 -0
- data/lib/hello_sense/api_error.rb +20 -0
- data/lib/hello_sense/app.rb +21 -0
- data/lib/hello_sense/client.rb +142 -0
- data/lib/hello_sense/constants.rb +4 -0
- data/lib/hello_sense/devices.rb +74 -0
- data/lib/hello_sense/expansions.rb +53 -0
- data/lib/hello_sense/firmware.rb +20 -0
- data/lib/hello_sense/insights.rb +57 -0
- data/lib/hello_sense/notifications.rb +36 -0
- data/lib/hello_sense/questions.rb +44 -0
- data/lib/hello_sense/sensors.rb +125 -0
- data/lib/hello_sense/session.rb +26 -0
- data/lib/hello_sense/sharing.rb +9 -0
- data/lib/hello_sense/sleep_sounds.rb +101 -0
- data/lib/hello_sense/speech.rb +14 -0
- data/lib/hello_sense/stats.rb +21 -0
- data/lib/hello_sense/store.rb +9 -0
- data/lib/hello_sense/support.rb +23 -0
- data/lib/hello_sense/timeline.rb +85 -0
- data/lib/hello_sense/trends.rb +109 -0
- data/lib/hello_sense/version.rb +5 -0
- metadata +197 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: a8e647726f67f5252d0c42deacd02db75b199fbb
|
4
|
+
data.tar.gz: 8aafd391d5d2ab33ce704bc64850ad9be5b431f4
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 815cb57782f3aa897b984a809c3f4f1eeb4368bbac81b18b39777df479db2480cc5e0d7b46d0fbafeb721eda0c52ef87e4a12c9e1e369212c5500c4fa84f6e4d
|
7
|
+
data.tar.gz: ae0e965c4fb843128eec6066e681ee619fc889f727eb8985c03ddae2fe02a01f5ac14b4787bfcb4932cb0cfb1b299f1a8172aeda220176b853894ec694780227
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
# Change Log
|
2
|
+
All notable changes to this project will be documented in this file.
|
3
|
+
|
4
|
+
The format is based on [Keep a Changelog](http://keepachangelog.com/)
|
5
|
+
and this project adheres to [Semantic Versioning](http://semver.org/).
|
6
|
+
|
7
|
+
## Unreleased
|
8
|
+
### Added
|
9
|
+
- Initial release
|
data/CONTRIBUTING.md
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
# Contributing to `hello-sense`
|
2
|
+
|
3
|
+
Thank you for your interest in contributing to the `hello-sense` gem! We welcome any contributions: code, bug reports, documentation, and more.
|
4
|
+
|
5
|
+
## Bug reports
|
6
|
+
|
7
|
+
There’s a number of reasons to file a bug report:
|
8
|
+
|
9
|
+
* incorrect or unexpected results
|
10
|
+
* bugs
|
11
|
+
* misleading or incorrect documentation
|
12
|
+
|
13
|
+
Opening an issue is as easy as following [this link](https://github.com/stilist/hello-sense/issues/new) and filling out the fields. You can reference the [template](.github/ISSUE_TEMPLATE.md) to see what information will be the most helpful.
|
14
|
+
|
15
|
+
## Development environment
|
16
|
+
|
17
|
+
To install the development dependencies, run these commands:
|
18
|
+
|
19
|
+
```bash
|
20
|
+
$ gem install bundler
|
21
|
+
$ bundle install
|
22
|
+
```
|
23
|
+
|
24
|
+
## Making changes
|
25
|
+
|
26
|
+
When you make changes to the code, make sure you’re keeping the [test suite](http://rspec.info) and [inline documentation](http://yardoc.org) updated.
|
27
|
+
|
28
|
+
When you’re done making your changes, run `rake build`. This automatically generates documentation (`rake doc`), [lints the code](https://github.com/bbatsov/rubocop) (`rake lint`), and runs the test suite (`rake spec`) before building the `.gem` file. If `rake build` finishes without any errors and builds the `.gem`, your changes are ready for a pull request.
|
29
|
+
|
30
|
+
## Pull requests
|
31
|
+
|
32
|
+
We use pull requests as a simple, consistent way to make updates to the project. GitHub has some [great documentation][pull-requests] on using the Pull Request feature. We use the ‘fork and pull’ model described there.
|
33
|
+
|
34
|
+
[pull-requests]: https://help.github.com/articles/using-pull-requests/
|
35
|
+
|
36
|
+
Please make pull requests against the `master` branch. We have a [pull request template](PULL_REQUEST_TEMPLATE.md) to help guide you.
|
37
|
+
|
38
|
+
## Coding conventions
|
39
|
+
|
40
|
+
Hello doesn't publicly document the Sense API, so this gem's documentation includes request and response data to demonstrate each API endpoint. To keep personal information out of the example data, use these values whenever you add or change documentation:
|
41
|
+
|
42
|
+
* email address: `drisha.wabudeya@example.org`
|
43
|
+
* name: [Drisha](http://www.bachpan.com/Meaning-Of-Drisha.aspx) [Wabudeya](http://www.americanlastnames.us/last-names/Ugandan/W/W-0.html)
|
44
|
+
* password: `'My super secure password!'`
|
45
|
+
* device id: `ABCDEF1234567890` or `0987654321FEDCBA`
|
46
|
+
* create timestamp: `1420099200000` (`2015-01-01T00:00:00-0800`)
|
47
|
+
* update timestamp: `1483257600000` (`2017-01-01T00:00:00-0800`)
|
48
|
+
* [UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier): `FDED667B-9E91-43F5-91DE-258AC1FEE9C2` (generated with [an online tool](https://guidgenerator.com/online-guid-generator.aspx))
|
49
|
+
|
50
|
+
|
51
|
+
|
52
|
+
|
53
|
+
|
54
|
+
|
55
|
+
* https://apkpure.com/sense/is.hello.sense
|
56
|
+
* https://github.com/skylot/jadx
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2017 Jordan Cole
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
# `hello-sense`
|
2
|
+
|
3
|
+
## Installation
|
4
|
+
|
5
|
+
```shell
|
6
|
+
gem install hello-sense
|
7
|
+
```
|
8
|
+
|
9
|
+
## Usage
|
10
|
+
|
11
|
+
### Authentication
|
12
|
+
|
13
|
+
The Sense API relies on an [OAuth 2](https://oauth.net/2/) [access token](https://www.oauth.com/oauth2-servers/access-tokens/).
|
14
|
+
|
15
|
+
(Note: the `client_id` and `client_secret` shown here are taken from the official Sense app's source code.)
|
16
|
+
|
17
|
+
```ruby
|
18
|
+
# Create a session using email and password.
|
19
|
+
client = Sense::Client.new(client_id: '8d3c1664-05ae-47e4-bcdb-477489590aa4',
|
20
|
+
client_secret: '4f771f6f-5c10-4104-bbc6-3333f5b11bf9',
|
21
|
+
username: 'drisha.wabudeya@example.org',
|
22
|
+
password: 'My super secure password!')
|
23
|
+
```
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
# Create a session using an existing access token.
|
27
|
+
client = Sense::Client.new(access_token: '2.fded667b9e9143f591de258ac1fee9c2')
|
28
|
+
```
|
29
|
+
|
30
|
+
```ruby
|
31
|
+
# Get the timeline for the sleep session from the night of 31 December 2016.
|
32
|
+
client.timeline('2017-01-01')
|
33
|
+
|
34
|
+
# Get the current conditions reported by the device's sensors.
|
35
|
+
client.sensors
|
36
|
+
```
|
37
|
+
|
38
|
+
```ruby
|
39
|
+
# Invalidate the session's access token.
|
40
|
+
client.destroy_token
|
41
|
+
```
|
42
|
+
|
43
|
+
```ruby
|
44
|
+
# Pull in ~38 days of sensor data, sampled at 5 minute intervals.
|
45
|
+
data = client.sensors_historical(hours: 920)
|
46
|
+
File.open('sense_sensor_data.json', 'w') { |f| f.write(JSON.dump(data) }
|
47
|
+
```
|
48
|
+
|
49
|
+
## Contributing
|
50
|
+
|
51
|
+
To contribute to the `hello-sense` gem, please see [`CONTRIBUTING`](CONTRIBUTING.md).
|
52
|
+
|
53
|
+
## References
|
54
|
+
|
55
|
+
* http://jeffhuang.com/extracting_my_data_from_the_hello_sense.html
|
data/hello_sense.gemspec
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require_relative 'lib/hello_sense/version'
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.date = Time.now.strftime('%Y-%m-%d')
|
5
|
+
s.description = "Ruby implementation of Sense's private API"
|
6
|
+
s.name = 'hello-sense'
|
7
|
+
s.required_ruby_version = ['>= 2.3.0', '< 2.5.0']
|
8
|
+
s.summary = 'TK'
|
9
|
+
s.version = Sense::VERSION
|
10
|
+
|
11
|
+
s.authors = ['Jordan Cole']
|
12
|
+
s.email = ['stilist@ratafia.info']
|
13
|
+
s.homepage = 'https://github.com/stilist/hello-sense'
|
14
|
+
|
15
|
+
s.files = Dir[__FILE__, 'LICENSE', '*.md', 'lib/**/*']
|
16
|
+
s.metadata['yard.run'] = 'yri'
|
17
|
+
|
18
|
+
s.add_development_dependency('byebug', '~> 9.0', '>= 9.0.0')
|
19
|
+
s.add_development_dependency('rake', '~> 11.0', '>= 11.0.0')
|
20
|
+
s.add_development_dependency('rspec-core', '~> 3.6', '>= 3.6.0')
|
21
|
+
s.add_development_dependency('rspec-expectations', '~> 3.6', '>= 3.6.0')
|
22
|
+
s.add_development_dependency('rubocop', '~> 0.48', '>= 0.48.0')
|
23
|
+
s.add_development_dependency('yard', '~> 0.9', '>= 0.9.0')
|
24
|
+
end
|
data/lib/hello_sense.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Defines the namespace for the +hello-sense+ gem.
|
4
|
+
module Sense
|
5
|
+
require_relative 'hello_sense/account'
|
6
|
+
require_relative 'hello_sense/alarms'
|
7
|
+
require_relative 'hello_sense/alerts'
|
8
|
+
require_relative 'hello_sense/app'
|
9
|
+
require_relative 'hello_sense/devices'
|
10
|
+
require_relative 'hello_sense/expansions'
|
11
|
+
require_relative 'hello_sense/firmware'
|
12
|
+
require_relative 'hello_sense/insights'
|
13
|
+
require_relative 'hello_sense/notifications'
|
14
|
+
require_relative 'hello_sense/questions'
|
15
|
+
require_relative 'hello_sense/sensors'
|
16
|
+
require_relative 'hello_sense/sharing'
|
17
|
+
require_relative 'hello_sense/sleep_sounds'
|
18
|
+
require_relative 'hello_sense/speech'
|
19
|
+
require_relative 'hello_sense/stats'
|
20
|
+
require_relative 'hello_sense/store'
|
21
|
+
require_relative 'hello_sense/support'
|
22
|
+
require_relative 'hello_sense/timeline'
|
23
|
+
require_relative 'hello_sense/trends'
|
24
|
+
|
25
|
+
require_relative 'hello_sense/api_error'
|
26
|
+
require_relative 'hello_sense/constants'
|
27
|
+
require_relative 'hello_sense/session'
|
28
|
+
require_relative 'hello_sense/version'
|
29
|
+
require_relative 'hello_sense/client'
|
30
|
+
end
|
@@ -0,0 +1,130 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Sense
|
4
|
+
module Account
|
5
|
+
EMAIL_PATTERN = /^.+@.+\\..+$/
|
6
|
+
MIN_PASSWORD_LENGTH = 6
|
7
|
+
|
8
|
+
# Get the current
|
9
|
+
#
|
10
|
+
# @return [Hash]
|
11
|
+
#
|
12
|
+
# @example
|
13
|
+
# {
|
14
|
+
# "email" => "drisha.wabudeya@example.org",
|
15
|
+
# "tz" => -28800000,
|
16
|
+
# "name" => "Drisha",
|
17
|
+
# "firstname" => "Drisha",
|
18
|
+
# "lastname" => "Wabudeya",
|
19
|
+
# "gender" => "FEMALE",
|
20
|
+
# "gender_other" => "",
|
21
|
+
# "height" => 160,
|
22
|
+
# "weight" => 68000,
|
23
|
+
# "created" => 1420099200000,
|
24
|
+
# "last_modified" => 1420099200000,
|
25
|
+
# "email_verified" => true,
|
26
|
+
# "profile_photo" => nil,
|
27
|
+
# "ext_id" => "fded667b-9e91-43f5-91de-258ac1fee9c2",
|
28
|
+
# "dob" => "1990-01-01",
|
29
|
+
# "id" => "fded667b-9e91-43f5-91de-258ac1fee9c2"
|
30
|
+
# }
|
31
|
+
|
32
|
+
def account
|
33
|
+
get('/v1/account')
|
34
|
+
end
|
35
|
+
|
36
|
+
# @param data [Hash]
|
37
|
+
#
|
38
|
+
# @see #account for fields
|
39
|
+
|
40
|
+
def create_account(data)
|
41
|
+
put('/v1/account', data)
|
42
|
+
end
|
43
|
+
|
44
|
+
# @param data [Hash]
|
45
|
+
#
|
46
|
+
# @see #account for fields
|
47
|
+
|
48
|
+
def update_account(data)
|
49
|
+
post('/v1/account', data)
|
50
|
+
end
|
51
|
+
|
52
|
+
# @return [Hash]
|
53
|
+
#
|
54
|
+
# @example
|
55
|
+
# {
|
56
|
+
# "TIME_TWENTY_FOUR_HOUR" => true,
|
57
|
+
# "PUSH_SCORE" => true,
|
58
|
+
# "WEIGHT_METRIC" => false,
|
59
|
+
# "TEMP_CELSIUS" => true,
|
60
|
+
# "HEIGHT_METRIC" => false,
|
61
|
+
# "ENHANCED_AUDIO" => true,
|
62
|
+
# "PUSH_ALERT_CONDITIONS" => true
|
63
|
+
# }
|
64
|
+
|
65
|
+
def preferences
|
66
|
+
get('/v2/account/preferences')
|
67
|
+
end
|
68
|
+
|
69
|
+
def update_preferences(data)
|
70
|
+
put('/v2/account/preferences', data)
|
71
|
+
end
|
72
|
+
|
73
|
+
def update_photo(data)
|
74
|
+
post('/v1/photo/profile', data)
|
75
|
+
end
|
76
|
+
|
77
|
+
def delete_profile_picture
|
78
|
+
delete('/v1/photo/profile')
|
79
|
+
end
|
80
|
+
|
81
|
+
# @param email [String] the new email address for the account
|
82
|
+
# @return XXX
|
83
|
+
|
84
|
+
def update_email(email)
|
85
|
+
raise InvalidEmailError if !normalize(email).match(EMAIL_PATTERN)
|
86
|
+
|
87
|
+
data = account.merge('email' => email)
|
88
|
+
|
89
|
+
post('/v1/account/email', data)
|
90
|
+
end
|
91
|
+
|
92
|
+
# @param current_password [String] the user's current password
|
93
|
+
# @param new_password [String] the new password to use
|
94
|
+
#
|
95
|
+
# @note
|
96
|
+
#
|
97
|
+
# @example
|
98
|
+
# client.update_password('My super secure password!',
|
99
|
+
# 'My even better new password (my second)!')
|
100
|
+
|
101
|
+
def update_password(current_password, new_password)
|
102
|
+
raise InvalidPasswordError if normalize(new_password).length < MIN_PASSWORD_LENGTH
|
103
|
+
|
104
|
+
post('/v1/account/password', currentPassword: current_password,
|
105
|
+
newPassword: new_password)
|
106
|
+
end
|
107
|
+
|
108
|
+
# @return [Hash]
|
109
|
+
#
|
110
|
+
# @example
|
111
|
+
# {
|
112
|
+
# "timezone_offset" => -25200000,
|
113
|
+
# "timezone_id" => "America/Los_Angeles"
|
114
|
+
# }
|
115
|
+
|
116
|
+
def current_timezone
|
117
|
+
get('/v1/timezone')
|
118
|
+
end
|
119
|
+
|
120
|
+
def update_timezone(data)
|
121
|
+
post('/v1/timezone', data)
|
122
|
+
end
|
123
|
+
|
124
|
+
private
|
125
|
+
|
126
|
+
def normalize(str = '')
|
127
|
+
str.trim
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Sense
|
4
|
+
module Alarms
|
5
|
+
# @return [Hash]
|
6
|
+
#
|
7
|
+
# @example
|
8
|
+
# {
|
9
|
+
# "expansions" => [],
|
10
|
+
# "voice" => [],
|
11
|
+
# "classic" => [{
|
12
|
+
# "year" => 0,
|
13
|
+
# "month" => 0,
|
14
|
+
# "day_of_month" => 0,
|
15
|
+
# "hour" => 7,
|
16
|
+
# "minute" => 30,
|
17
|
+
# "day_of_week" => [1, 2, 3, 4, 5],
|
18
|
+
# "repeated" => true,
|
19
|
+
# "enabled" => true,
|
20
|
+
# "editable" => true,
|
21
|
+
# "smart" => true,
|
22
|
+
# "sound" => {
|
23
|
+
# "id" => 5,
|
24
|
+
# "name" => "Dusk",
|
25
|
+
# "url" => ""
|
26
|
+
# },
|
27
|
+
# "id" => "FDED667B-9E91-43F5-91DE-258AC1FEE9C2",
|
28
|
+
# "source" => "MOBILE_APP",
|
29
|
+
# "expansions" => []
|
30
|
+
# }]
|
31
|
+
# }
|
32
|
+
|
33
|
+
def alarms
|
34
|
+
get('/v2/alarms')
|
35
|
+
end
|
36
|
+
|
37
|
+
# @return [Array<Hash>]
|
38
|
+
#
|
39
|
+
# @example
|
40
|
+
# [
|
41
|
+
# {
|
42
|
+
# "id" => 5,
|
43
|
+
# "name" => "Dusk",
|
44
|
+
# "url" => "https://hello-audio.s3.amazonaws.com/ringtones/Dusk.mp3?x-amz-security-token=XXX"
|
45
|
+
# },
|
46
|
+
# ]
|
47
|
+
|
48
|
+
def alarm_sounds
|
49
|
+
get('/v1/alarms/sounds')
|
50
|
+
end
|
51
|
+
|
52
|
+
def update_alarm(data)
|
53
|
+
timestamp = DateTime.now
|
54
|
+
.new_offset(0)
|
55
|
+
.iso8601
|
56
|
+
post("/v2/alarms/#{timestamp}", data)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Sense
|
4
|
+
class APIError < StandardError
|
5
|
+
attr_reader :code, :description, :response, :type
|
6
|
+
|
7
|
+
# @todo Document param
|
8
|
+
def initialize(response)
|
9
|
+
@code = response.code
|
10
|
+
@description = response.code_type
|
11
|
+
@response = response
|
12
|
+
@type = response.error_type
|
13
|
+
end
|
14
|
+
|
15
|
+
def message
|
16
|
+
"#{@type}: #{@description} (#{@code})"
|
17
|
+
end
|
18
|
+
alias to_s message
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Sense
|
4
|
+
module App
|
5
|
+
# Check if a new version of the app has been released.
|
6
|
+
#
|
7
|
+
# @param app_version [String]
|
8
|
+
# @param language [String]
|
9
|
+
# @param platform [String]
|
10
|
+
# @return [Hash]
|
11
|
+
#
|
12
|
+
# @example
|
13
|
+
# client.check_for_update('10000000', 'en', 'android')
|
14
|
+
|
15
|
+
def check_for_update(app_version, language, platform)
|
16
|
+
post('/v1/app/checkin', app_version: app_version,
|
17
|
+
lang_code: language,
|
18
|
+
platform: platform)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|