particlerb 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c21a444cf3a1c9100b0c8c8d9b70105ee65e28dc
4
- data.tar.gz: 9d7b3d4150a9c4d4f69306f47c411761c7a6d06b
3
+ metadata.gz: 3df82a4b9e831fa635c52d24e9d0f59bd3b6209d
4
+ data.tar.gz: 61c6aa2eba790faeee99e4cde8ea6f04e214946b
5
5
  SHA512:
6
- metadata.gz: 6daacb4b3fb434bfa5d5f250e2c7b90784b8e8319643998bce95732e7c6b47520e4fe9aa96767b4d2fd6e1b576b5f759bffe37de43281205d65c7ecc3a8e6bcd
7
- data.tar.gz: f6cd397e20992d386419f36e889fcdcdaeda9ae007777900752c847d1e5c99ca94cc79980b41989d7c6cf1b04140d8bd6766c5905d63cc71301bc2999a207643
6
+ metadata.gz: 4a4f275a4d1b7b1dde368e620a76205e4ee34fd23aaca4682d3df0bee6c3407786504d05b648cfe56ddb8ea0e88404a69d5a3479705e58ee6e9eb2276cb5f1d5
7
+ data.tar.gz: 95e421509a8109498915efcb25096969204afb0fb673a38edca51957ea20874d784a9dca23383e5d6cce600bb65e429f0ad7b8048b8de06985eb09b7c8d6d32f
data/README.md CHANGED
@@ -1,12 +1,16 @@
1
- # particlerb [![Build Status](https://travis-ci.org/monkbroc/particlerb.svg)](https://travis-ci.org/monkbroc/particlerb)
1
+ ## particlerb ##
2
2
 
3
- Ruby client for the [Particle.io] Cloud API
3
+ [![Gem Version](https://badge.fury.io/rb/particlerb.svg)](http://badge.fury.io/rb/particlerb)
4
+ [![Build Status](https://travis-ci.org/monkbroc/particlerb.svg)](https://travis-ci.org/monkbroc/particlerb)
5
+ [![Code Climate](https://codeclimate.com/github/monkbroc/particlerb/badges/gpa.svg)](https://codeclimate.com/github/monkbroc/particlerb)
6
+
7
+ Ruby client for the [Particle.io] Cloud API with an object-oriented interface
4
8
 
5
9
  [Particle.io]: https://www.particle.io
6
10
 
7
11
  *Note: this is not an official gem by Particle. It is maintained by Julien Vanier.*
8
12
 
9
- ## Quick start
13
+ ## Installation
10
14
 
11
15
  Install via Rubygems
12
16
 
@@ -14,82 +18,111 @@ Install via Rubygems
14
18
 
15
19
  ... or add to your Gemfile
16
20
 
17
- gem "particlerb", "~> 0.0.1"
21
+ gem "particlerb", "~> 0.0.2"
18
22
 
19
23
 
20
- ### Making requests
24
+ ### Providing credentials
21
25
 
22
- API methods are available as module methods (consuming module-level
23
- configuration) or as client instance methods.
26
+ **A Particle cloud API access token is necessary for most requests.** You can use the one from the [Web IDE][] for testing, but it's recommended to generate a new token with this gem using `Particle.login` or with the [Particle CLI][] using `particle token new`
24
27
 
25
28
  ```ruby
26
- # Provide authentication credentials
29
+ # Provide acess token as an environment variable
30
+ ENV['PARTICLE_ACCESS_TOKEN']
31
+
32
+ # Or configure global authentication credentials
33
+ # If you use Rails, you can put this in config/initializers/particle.rb
27
34
  Particle.configure do |c|
28
35
  c.access_token = "38bb7b318cc6898c80317decb34525844bc9db55"
29
36
  end
30
37
 
31
- # Fetch the list of devices
32
- Particle.devices
38
+ # Or pass access token when creating a client
39
+ # If no token is passed to Particle::Client.new, the global or environment one is used
40
+ client = Particle::Client.new(access_token: "38bb7b318cc6898c80317decb34525844bc9db55")
33
41
  ```
34
- or
42
+
43
+ ### Making requests
44
+
45
+ API methods are available as module methods (consuming module-level
46
+ configuration) or as client instance methods.
35
47
 
36
48
  ```ruby
37
- # Provide authentication credentials
38
- client = Particle::Client.new(access_token: "38bb7b318cc6898c80317decb34525844bc9db55")
49
+ # Fetch the list of devices using the global client
50
+ Particle.devices
51
+
52
+ # Or used a newly created client
53
+ client = Particle::Client.new
39
54
  # Fetch the list of devices
40
55
  client.devices
41
56
  ```
42
57
 
43
- ## Device commands
58
+ [Web IDE]: http://docs.particle.io/core/build/#flash-apps-with-particle-build-account-information
59
+ [Particle CLI]: http://docs.particle.io/core/cli
60
+
61
+ ## Interacting with devices
44
62
 
45
- See the [Particle Cloud API documentation][API docs] for more details.
63
+ List all devices. Rreturns an `Array` of `Particle::Device`.
46
64
 
47
- List all devices (returns an `Array` of `Device`)
48
65
  ```ruby
49
66
  devices = Particle.devices
50
67
  ```
51
68
 
52
- Get a `Device` by id or name
69
+ Get a `Particle::Device` by id or name.
70
+
53
71
  ```ruby
54
72
  device = Particle.device('blue_fire')
55
73
  device = Particle.device('f8bbe1e6e69e05c9c405ba1ca504d438061f1b0d')
56
74
  ```
57
75
 
58
- Get information about a device
76
+ Get information about a device.
77
+
59
78
  ```ruby
60
79
  device = Particle.device('blue_fire')
61
- device.id
62
- device.name
63
- device.connected?
64
- device.variables
65
- device.functions
66
80
  device.attributes # Hash of all attributes
81
+ device.id # ==> 'f8bbe1e6e69e05c9c405ba1ca504d438061f1b0d'
82
+ device.name # ==> 'blue_fire'
83
+ device.connected? # true
84
+ device.variables # {:myvar => "double" } or nil if not connected
85
+ device.functions # ["myfunction"] or nil if not connected
67
86
  device.get_attributes # forces refresh of all attributes from the cloud
87
+
88
+ # If you get a Device from the Particle.devices call, you will need to call
89
+ # get_attributes to get the list of functions and variables since that's not
90
+ # returned by the cloud when calling Particle.devices
91
+ device = Particle.devices.first
92
+ device.connected? # ==> true
93
+ device.functions # ==> nil
94
+ device.get_attributes
95
+ device.functions # ==> ["myfunction"]
68
96
  ```
69
97
 
70
- Claim a device and add it to your account (returns the `Device`)
98
+ Claim a device by id and add it to your account. Returns a `Particle::Device`.
99
+
71
100
  ```ruby
72
- Particle.device('blue_fire').claim
101
+ Particle.device('f8bbe1e6e69e05c9c405ba1ca504d438061f1b0d').claim
73
102
  ```
74
103
 
75
- Remove a device from your account
104
+ Remove a device from your account. Returns true on success.
105
+
76
106
  ```ruby
77
107
  Particle.device('blue_fire').remove
78
108
  Particle.devices.first.remove
79
109
  ```
80
110
 
81
- Rename a device
111
+ Rename a device. Returns true on success.
112
+
82
113
  ```ruby
83
114
  Particle.device('red').rename('green')
84
115
  ```
85
116
 
86
- Call a function on the firmware (returns the result of running the function)
117
+ Call a function on the firmware with an optional `String` argument. Returns the result of running the function as as `Number`.
118
+
87
119
  ```ruby
88
- Particle.device('coffeemaker').function('brew') # String argument optional
120
+ Particle.device('coffeemaker').function('brew')
89
121
  Particle.devices.first.function('digitalWrite', '1')
90
122
  ```
91
123
 
92
- Get the value of a firmware variable (returns the result as a String or Number)
124
+ Get the value of a firmware variable. Returns the result as a `String` or `Number`.
125
+
93
126
  ```ruby
94
127
  Particle.device('mycar').variable('battery') # ==> 12.33
95
128
  device = Particle.device('f8bbe1e6e69e05c9c405ba1ca504d438061f1b0d')
@@ -97,13 +130,145 @@ device.variable('version') # ==> "1.0.1"
97
130
  ```
98
131
 
99
132
 
100
- Signal a device to start blinking the RGB LED in rainbow patterns.
133
+ Signal a device to start blinking the RGB LED in rainbow patterns. Returns whether the device is signaling.
134
+
101
135
  ```ruby
102
136
  Particle.device('nyan_cat').signal(true)
103
137
  ```
138
+ See the [Particle Cloud API documentation about devices][device docs] for more details.
139
+
140
+ [device docs]: http://docs.particle.io/core/api/#introduction-device-information
141
+
142
+ ## Interacting with events
143
+
144
+ Publish an event to your devices. Returns true on success.
145
+
146
+ ```ruby
147
+ Particle.publish(name: "wakeup")
148
+ Particle.publish(name: "server_ip", data: "8.8.8.8", ttl: 3600, private: true)
149
+ ```
150
+
151
+ Data, ttl and private are optional.
152
+
153
+ Data is converted to JSON if it is a Hash or an Array, otherwise it is converted to a String.
154
+
155
+ See the [Particle Cloud API documentation about publishing events][publish docs] for more details.
156
+
157
+ [publish docs]: http://docs.particle.io/core/api/#publishing-events
158
+
159
+ ### Limitation: Subscribe not supported
160
+
161
+ This gem does not support subscribing (listening) to events from devices.
162
+
163
+ This would require an HTTP client that supports streaming responses which is not common in Ruby. Some clients like EM-HTTP-Request do support streaming responses, but are tied to specific architectures like EventMachine.
164
+
165
+ For web server applications, webhooks are better suited to process incoming events.
166
+
167
+ ## Interacting with webhooks
168
+
169
+ List existing webhooks. Returns an `Array` of `Particle::Webhook`
170
+
171
+ ```ruby
172
+ Particle.webhooks
173
+ ```
174
+
175
+ Get info about an existing webhook by id. Returns a `Particle::Webhook`
176
+
177
+ ```ruby
178
+ webhook = Particle.webhook('ffcddbd30b860ea3cadd22db')
179
+ webhook.attributes
180
+ webhook.event
181
+ webhook.url
182
+ ```
183
+
184
+ Calling `attributes` will also send a test message to your webhook url and report the `response` or `error`.
185
+
186
+ ```ruby
187
+ webhook.response
188
+ webhook.error
189
+
190
+ webhook = Particle.webhooks.first
191
+ webhook.get_attributes # force reloading attributes from the cloud
192
+ # get_attributes necessary to get the response when Webhook was returned from the
193
+ # Particle.webhooks() method as it doesn't do a test message on each webhook
194
+ webhook.response
195
+ ```
196
+
197
+ Create a new webhook. Pass a hash of [any options accepted by the Particle Cloud API][webhook options]. Returns a `Particle::Webhook`
198
+
199
+ ```ruby
200
+ Particle.webhook(event: "weather", url: "http://myserver.com/report").create
201
+ ```
202
+ See the [Particle Cloud API documentation about webhooks][webhook docs] for more details.
203
+
204
+ [webhook docs]: http://docs.particle.io/core/webhooks/
205
+ [webhook options]: http://docs.particle.io/core/webhooks/#webhook-options
206
+
207
+ ## Authentication
208
+
209
+ Replace the access token on a client
210
+
211
+ ```ruby
212
+ Particle.access_token = 'f1d52ea0de921fad300027763d8c5ebd03b1934d'
213
+
214
+ # On client instance
215
+ client = Particle::Client.new
216
+ client.access_token = 'f1d52ea0de921fad300027763d8c5ebd03b1934d'
217
+ ```
218
+
219
+ **All these following methods requires the account username (email) and password.**
220
+
221
+ List all tokens that can be used to access an account. Returns an `Array` of `Particle::Token`
222
+
223
+ ```ruby
224
+ Particle.tokens("me@example.com", "pa$$w0rd")
225
+ ```
226
+
227
+ Log in and create a new token. Returns a `Particle::Token`. This will also set the token on the client for future calls.
228
+
229
+ ```ruby
230
+ Particle.login("me@example.com", "pa$$w0rd")
231
+ ```
232
+
233
+ Create a token but don't set it on the client. Returns a `Particle::Token`
234
+
235
+ ```ruby
236
+ Particle.token.create("me@example.com", "pa$$w0rd")
237
+ ```
238
+
239
+ Invalidate and delete a token. Returns true on success.
240
+
241
+ ```ruby
242
+ Particle.token('f1d52ea0de921fad300027763d8c5ebd03b1934d').remove("me@example.com", "pa$$w0rd")
243
+ Particle.tokens.first.remove("me@example.com", "pa$$w0rd")
244
+ ```
245
+
246
+ See the [Particle Cloud API documentation about authentication and token][authentication docs] for more details.
247
+
248
+ [authentication docs]: http://docs.particle.io/core/api/#introduction-authentication
249
+
104
250
 
251
+ ## Errors
105
252
 
106
- [API docs]: http://docs.particle.io/core/api
253
+ When any API error occurs, a subclass of `Particle::Error` will be raised.
254
+
255
+ The actual error classes are
256
+
257
+ - `MissingTokenError`
258
+ - `BadRequest`
259
+ - `Unauthorized`
260
+ - `Forbidden`
261
+ - `NotFound`
262
+ - `TimedOut`
263
+ - `ServerError`
264
+
265
+ See [a description of each error on the Particle API docs][error docs].
266
+
267
+ [error docs]: http://docs.particle.io/core/api/#introduction-errors
268
+
269
+ ## Advanced
270
+
271
+ All API endpoints are availble directly on the client object as method calls like `Particle.claim_device(id)` but the preferred usage is to call methods on domain objects like `Particle.device(id).claim`. See the various `Particle::Client` subclasses for more details.
107
272
 
108
273
  ### Accessing HTTP responses
109
274
 
@@ -117,6 +282,19 @@ response = Particle.last_response
117
282
  headers = response.headers
118
283
  ```
119
284
 
285
+ ## Support
286
+
287
+ Open a [GitHub issue][] if you find a bug.
288
+
289
+ [Join the conversion on the awesome Particle community forums][forum] to discuss any other topic!
290
+
291
+ [GitHub issue]: https://github.com/monkbroc/particlerb/issues
292
+ [forum]: http://community.particle.io/
293
+
294
+ ## Versioning
295
+
296
+ particlerb follows the [Semantic Versioning](http://semver.org/) standard.
297
+
120
298
  ## Thanks
121
299
 
122
300
  This gem is heavily inspired by [Octokit][] by GitHub. I stand on the shoulder of giants. Thanks!
@@ -1,13 +1,16 @@
1
+ require 'particle/device'
2
+
1
3
  module Particle
2
4
  class Client
3
5
 
4
- # Methods for the Particle device API
6
+ # Client methods for the Particle device API
7
+ #
5
8
  # @see http://docs.particle.io/core/api/#introduction-list-devices
6
9
  module Devices
7
10
 
8
11
  # Create a domain model for a Particle device
9
12
  #
10
- # @param target [String, Sawyer::Resource, Device] A device id, name or {Device} object
13
+ # @param target [String, Sawyer::Resource, Device] A device id, name, Sawyer::Resource or {Device} object
11
14
  # @return [Device] A device object to interact with
12
15
  def device(target)
13
16
  if target.is_a? Device
@@ -15,18 +18,16 @@ module Particle
15
18
  elsif target.respond_to?(:to_attrs)
16
19
  Device.new(self, target.to_attrs)
17
20
  else
18
- Device.new(self, target.to_s)
21
+ Device.new(self, target)
19
22
  end
20
23
  end
21
24
 
22
25
  # List all Particle devices on the account
23
26
  #
24
- # @see http://docs.particle.io/core/api/#introduction-list-devices
25
- #
26
27
  # @return [Array<Device>] List of Particle devices to interact with
27
28
  def devices
28
29
  get(Device.list_path).map do |resource|
29
- Device.new(self, resource)
30
+ device(resource)
30
31
  end
31
32
  end
32
33
 
@@ -0,0 +1,38 @@
1
+ require 'particle/event'
2
+
3
+ module Particle
4
+ class Client
5
+
6
+ # Client methods for the Particle publish API
7
+ #
8
+ # @see http://docs.particle.io/core/api/#publishing-events
9
+ module Publish
10
+
11
+ # Publish an event to your devices
12
+ #
13
+ # @param options [Hash]
14
+ # * :name [String]: name of the event to publish
15
+ # * :data [String,Hash]: optional data to include with the event
16
+ # * :ttl [Number]: optional Time-To-Live in seconds for the
17
+ # event (currently ignored by the cloud)
18
+ # * :private [boolean]: optional key to indicate event should
19
+ # be published only to your own devices
20
+ # @return [boolean] true for success
21
+ def publish(options)
22
+ params = {
23
+ name: options.fetch(:name)
24
+ }
25
+ case options[:data]
26
+ when Hash, Array then params[:data] = options[:data].to_json
27
+ else params[:data] = options[:data].to_s
28
+ end
29
+
30
+ params[:ttl] = options[:ttl] if options[:ttl]
31
+ params[:private] = true if options[:private]
32
+
33
+ result = post(Event.publish_path, params)
34
+ result.ok
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,101 @@
1
+ require 'particle/token'
2
+ require 'uri'
3
+
4
+ module Particle
5
+ class Client
6
+
7
+ # Client methods for the Particle authentication/token API
8
+ #
9
+ # @see http://docs.particle.io/core/api/#introduction-authentication
10
+ module Tokens
11
+
12
+ # Create a domain model for a Particle token
13
+ #
14
+ # @param target [String, Sawyer::Resource, Token] A token id, Sawyer::Resource or {Token} object
15
+ # @return [Token] A token object to interact with
16
+ def token(target = {})
17
+ if target.is_a? Token
18
+ target
19
+ elsif target.respond_to?(:to_attrs)
20
+ Token.new(self, target.to_attrs)
21
+ else
22
+ Token.new(self, target)
23
+ end
24
+ end
25
+
26
+ # List all Particle tokens for the account
27
+ #
28
+ # @param username [String] The username (email) used to log in to
29
+ # the Particle Cloud API
30
+ # @param password [String] The password used to log in to
31
+ # the Particle Cloud API
32
+ # @return [Array<Token>] List of Particle tokens
33
+ def tokens(username, password)
34
+ http_options = {
35
+ username: username,
36
+ password: password
37
+ }
38
+ request(:get, Token.list_path, "", http_options).map do |resource|
39
+ token(resource)
40
+ end
41
+ end
42
+
43
+ # Authenticate with Particle and create a new token
44
+ #
45
+ # @param username [String] The username (email) used to log in to
46
+ # the Particle Cloud API
47
+ # @param password [String] The password used to log in to
48
+ # the Particle Cloud API
49
+ # @param options [Hash] Additional Particle Cloud API options to
50
+ # create the token.
51
+ # @return [Token] The token object
52
+ def create_token(username, password, options = {})
53
+ data = URI.encode_www_form({
54
+ grant_type: 'password', # specified by docs
55
+ username: username,
56
+ password: password
57
+ }.merge(options))
58
+ http_options = {
59
+ headers: { content_type: "application/x-www-form-urlencoded" },
60
+ username: 'particle', # specified by docs
61
+ password: 'particle' # specified by docs
62
+ }
63
+ result = request(:post, Token.create_path, data, http_options)
64
+ token(result.access_token)
65
+ end
66
+
67
+ # Authenticate with Particle and start using the token on the
68
+ # client right away
69
+ #
70
+ # @param username [String] The username (email) used to log in to
71
+ # the Particle Cloud API
72
+ # @param password [String] The password used to log in to
73
+ # the Particle Cloud API
74
+ # @param options [Hash] Additional Particle Cloud API options to
75
+ # create the token.
76
+ # @return [Token] The token object
77
+ def login(username, password, options = {})
78
+ token = create_token(username, password, options)
79
+ self.access_token = token
80
+ token
81
+ end
82
+
83
+ # Remove a Particle token
84
+ #
85
+ # @param username [String] The username (email) used to log in to
86
+ # the Particle Cloud API
87
+ # @param password [String] The password used to log in to
88
+ # the Particle Cloud API
89
+ # @param target [String, Token] An token id or {Token} object
90
+ # @return [boolean] true for success
91
+ def remove_token(username, password, target)
92
+ http_options = {
93
+ username: username,
94
+ password: password
95
+ }
96
+ result = request(:delete, token(target).path, "", http_options)
97
+ result.ok
98
+ end
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,66 @@
1
+ require 'particle/webhook'
2
+
3
+ module Particle
4
+ class Client
5
+
6
+ # Client methods for the Particle webhook API
7
+ #
8
+ # @see http://docs.particle.io/core/webhooks/
9
+ module Webhooks
10
+
11
+ # Create a domain model for a Particle webhook
12
+ #
13
+ # @param target [String, Sawyer::Resource, Webhook] A webhook id, Sawyer::Resource or {Device} object
14
+ # @return [Webhook] A webhook object to interact with
15
+ def webhook(target)
16
+ if target.is_a? Webhook
17
+ target
18
+ elsif target.respond_to?(:to_attrs)
19
+ Webhook.new(self, target.to_attrs)
20
+ else
21
+ Webhook.new(self, target)
22
+ end
23
+ end
24
+
25
+ # List all Particle webhooks on the account
26
+ #
27
+ # @return [Array<Webhook>] List of Particle webhooks to interact with
28
+ def webhooks
29
+ get(Webhook.list_path).map do |resource|
30
+ webhook(resource)
31
+ end
32
+ end
33
+
34
+ # Get information about a Particle webhook
35
+ #
36
+ # The Particle cloud will send a test message to the webhook URL
37
+ # when this is called
38
+ #
39
+ # @param target [String, Webhook] A webhook id or {Webhook} object
40
+ # @return [Hash] The webhook attributes and test message response
41
+ def webhook_attributes(target)
42
+ result = get(webhook(target).path)
43
+ result.to_attrs
44
+ end
45
+
46
+ # Creates a new Particle webhook
47
+ #
48
+ # @param options [Hash] Options to configure the webhook
49
+ # @return [Webhook] The webhook object
50
+ # @see http://docs.particle.io/core/webhooks/#Webhook-options
51
+ def create_webhook(options)
52
+ result = post(Webhook.create_path, options)
53
+ webhook(result)
54
+ end
55
+
56
+ # Remove a Particle webhook
57
+ #
58
+ # @param target [String, Webhook] A webhook id or {Webhook} object
59
+ # @return [boolean] true for success
60
+ def remove_webhook(target)
61
+ result = delete(webhook(target).path)
62
+ result.ok
63
+ end
64
+ end
65
+ end
66
+ end
@@ -1,6 +1,8 @@
1
1
  require 'particle/connection'
2
- require 'particle/device'
3
2
  require 'particle/client/devices'
3
+ require 'particle/client/publish'
4
+ require 'particle/client/webhooks'
5
+ require 'particle/client/tokens'
4
6
 
5
7
  module Particle
6
8
 
@@ -11,6 +13,9 @@ module Particle
11
13
  include Particle::Configurable
12
14
  include Particle::Connection
13
15
  include Particle::Client::Devices
16
+ include Particle::Client::Publish
17
+ include Particle::Client::Webhooks
18
+ include Particle::Client::Tokens
14
19
 
15
20
  def initialize(options = {})
16
21
  # Use options passed in, but fall back to module defaults
@@ -38,7 +43,12 @@ module Particle
38
43
  # @param value [String] 40 character Particle OAuth2 access token
39
44
  def access_token=(value)
40
45
  reset_agent
41
- @access_token = value
46
+ @access_token =
47
+ if value.respond_to? :access_token
48
+ value.access_token
49
+ else
50
+ value
51
+ end
42
52
  end
43
53
  end
44
54
  end
@@ -3,7 +3,7 @@ module Particle
3
3
  # Configuration options for {Client}, defaulting to values in
4
4
  # {Default}
5
5
  module Configurable
6
- # @!attribute [w] access_token
6
+ # @!attribute [String] access_token
7
7
  # @see http://docs.particle.io/core/api/#introduction-authentication
8
8
  # @return [String] Particle access token for authentication
9
9
  # @!attribute api_endpoint
@@ -57,15 +57,6 @@ module Particle
57
57
  request :delete, url, options
58
58
  end
59
59
 
60
- # Make a HTTP HEAD request
61
- #
62
- # @param url [String] The path, relative to {#api_endpoint}
63
- # @param options [Hash] Query and header params for request
64
- # @return [Sawyer::Resource]
65
- def head(url, options = {})
66
- request :head, url, parse_query_and_convenience_headers(options)
67
- end
68
-
69
60
  # Hypermedia agent for the Particle API
70
61
  #
71
62
  # @return [Sawyer::Agent]
@@ -98,13 +89,21 @@ module Particle
98
89
 
99
90
  def request(method, path, data, options = {})
100
91
  if data.is_a?(Hash)
101
- options[:query] = data.delete(:query) || {}
102
- options[:headers] = data.delete(:headers) || {}
92
+ options[:query] ||= data.delete(:query) || {}
93
+ options[:headers] ||= data.delete(:headers) || {}
103
94
  if accept = data.delete(:accept)
104
95
  options[:headers][:accept] = accept
105
96
  end
106
97
  end
107
98
 
99
+ username = options.delete(:username)
100
+ password = options.delete(:password)
101
+ if username && password
102
+ options[:headers] ||= {}
103
+ options[:headers][:authorization] =
104
+ basic_auth_header(username, password)
105
+ end
106
+
108
107
  @last_response = response = agent.call(method, URI::Parser.new.escape(path.to_s), data, options)
109
108
  response.data
110
109
  end
@@ -120,6 +119,12 @@ module Particle
120
119
 
121
120
  opts
122
121
  end
122
+
123
+ # Temporarily set the Authorization to use basic auth
124
+ def basic_auth_header(username, password)
125
+ Faraday::Request.lookup_middleware(:basic_auth).
126
+ header(username, password)
127
+ end
123
128
  end
124
129
  end
125
130
 
@@ -1,20 +1,20 @@
1
+ require 'particle/model'
2
+
1
3
  module Particle
2
4
 
3
5
  # Domain model for one Particle device
4
- class Device
6
+ class Device < Model
5
7
  ID_REGEX = /\h{24}/
6
8
 
7
9
  def initialize(client, attributes)
8
- @client = client
9
- @attributes =
10
+ super(client, attributes)
11
+
10
12
  if attributes.is_a? String
11
13
  if attributes =~ ID_REGEX
12
- { id: attributes }
14
+ @attributes = { id: attributes }
13
15
  else
14
- { name: attributes }
16
+ @attributes = { name: attributes }
15
17
  end
16
- else
17
- attributes
18
18
  end
19
19
  end
20
20
 
@@ -32,17 +32,10 @@ module Particle
32
32
  @attributes[:id] || @attributes[:name]
33
33
  end
34
34
 
35
- %w(connected functions variables product_id last_heard).each do |key|
36
- define_method key do
37
- attributes[key.to_sym]
38
- end
39
- end
40
- alias_method :connected?, :connected
35
+ attribute_reader :connected, :functions, :variables, :product_id,
36
+ :last_heard, :last_app, :last_ip_address
41
37
 
42
- def attributes
43
- get_attributes unless @loaded
44
- @attributes
45
- end
38
+ alias_method :connected?, :connected
46
39
 
47
40
  def get_attributes
48
41
  @loaded = true
@@ -1,5 +1,7 @@
1
1
  module Particle
2
2
  # Custom error class for rescuing from all Particle errors
3
+ #
4
+ # @see http://docs.particle.io/core/api/#introduction-errors
3
5
  class Error < StandardError
4
6
 
5
7
  # Returns the appropriate Particle::Error subclass based
@@ -0,0 +1,10 @@
1
+ module Particle
2
+
3
+ # Domain model for Particle event
4
+ class Event
5
+ def self.publish_path
6
+ "v1/devices/events"
7
+ end
8
+ end
9
+ end
10
+
@@ -0,0 +1,49 @@
1
+ module Particle
2
+
3
+ # Base class for domain models
4
+ class Model
5
+ def initialize(client, attributes)
6
+ @client = client
7
+ @attributes =
8
+ if attributes.is_a? String
9
+ { id: attributes }
10
+ else
11
+ # Consider attributes loaded when passed in through constructor
12
+ @loaded = true
13
+ attributes
14
+ end
15
+ end
16
+
17
+ # Display the attributes when inspecting the object in the console
18
+ def inspect
19
+ "#<#{self.class} #{@attributes}>"
20
+ end
21
+
22
+ # Accessor for the id
23
+ def id
24
+ @attributes[:id]
25
+ end
26
+
27
+ # Define accessor methods for attributes.
28
+ #
29
+ # Will load the attributes from the cloud if not already done
30
+ def self.attribute_reader(*keys)
31
+ keys.each do |key|
32
+ define_method key do
33
+ attributes[key]
34
+ end
35
+ end
36
+ end
37
+
38
+ # Hash of all attributes returned by the cloud
39
+ def attributes
40
+ get_attributes unless @loaded
41
+ @attributes
42
+ end
43
+
44
+ # Load the model attributes with the correct API call in subclasses
45
+ def get_attributes
46
+ raise "Implement in subclasses and set @loaded = true"
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,76 @@
1
+ module Particle
2
+
3
+ # Domain model for one Particle token
4
+ class Token < Model
5
+ def initialize(client, attributes)
6
+ @client = client
7
+ @attributes =
8
+ if attributes.is_a? String
9
+ { token: attributes }
10
+ else
11
+ # Consider attributes loaded when passed in through constructor
12
+ @loaded = true
13
+ attributes
14
+ end
15
+ end
16
+
17
+ # The id of the token
18
+ def token
19
+ @attributes[:token]
20
+ end
21
+ alias_method :id, :token
22
+ alias_method :access_token, :token
23
+
24
+ attribute_reader :expires_at, :client
25
+
26
+ # Tokens can't be loaded. What you see is what you get...
27
+ def get_attributes
28
+ @loaded = true
29
+ @attributes
30
+ end
31
+
32
+ # Text representation of the token, masking the secret part
33
+ #
34
+ # @return [String]
35
+ def inspect
36
+ inspected = super
37
+
38
+ # Only show last 4 of token, secret
39
+ if id
40
+ inspected = inspected.gsub! id, "#{'*'*36}#{id[36..-1]}"
41
+ end
42
+
43
+ inspected
44
+ end
45
+
46
+ # Create a Particle token
47
+ # @param username [String] The username (email) used to log in to
48
+ # the Particle Cloud API
49
+ # @param password [String] The password used to log in to
50
+ # the Particle Cloud API
51
+ def create(username, password)
52
+ @client.create_token(username, password)
53
+ end
54
+
55
+ # Remove a Particle token
56
+ # @param username [String] The username (email) used to log in to
57
+ # the Particle Cloud API
58
+ # @param password [String] The password used to log in to
59
+ # the Particle Cloud API
60
+ def remove(username, password)
61
+ @client.remove_token(username, password, self)
62
+ end
63
+
64
+ def self.list_path
65
+ "v1/access_tokens"
66
+ end
67
+
68
+ def self.create_path
69
+ "/oauth/token"
70
+ end
71
+
72
+ def path
73
+ "/v1/access_tokens/#{access_token}"
74
+ end
75
+ end
76
+ end
@@ -1,3 +1,3 @@
1
1
  module Particle
2
- VERSION = "0.0.1".freeze
2
+ VERSION = "0.0.2".freeze
3
3
  end
@@ -0,0 +1,62 @@
1
+ require 'particle/model'
2
+
3
+ module Particle
4
+
5
+ # Domain model for one Particle device
6
+ class Webhook < Model
7
+ def initialize(client, attributes)
8
+ super(client, attributes)
9
+ end
10
+
11
+ attribute_reader :url, :deviceID, :event, :created_at, :mydevices,
12
+ :requestType, :headers, :json, :query, :auth
13
+
14
+ # The response of the web server to a test message
15
+ # If nil, check error
16
+ def response
17
+ get_attributes unless @loaded
18
+ @response
19
+ end
20
+
21
+ # The error from the web server to a test message
22
+ # If nil, check response
23
+ def error
24
+ get_attributes unless @loaded
25
+ @error
26
+ end
27
+
28
+ # Force reloading the attributes for the webhook
29
+ def get_attributes
30
+ @loaded = true
31
+ result = @client.webhook_attributes(self)
32
+ @response = result[:response]
33
+ @error = result[:error]
34
+ @attributes = result[:webhook]
35
+ end
36
+
37
+ # Add a Particle webhook
38
+ def create
39
+ new_webhook = @client.create_webhook(@attributes)
40
+ @attributes = new_webhook.attributes
41
+ self
42
+ end
43
+
44
+ # Remove a Particle webhook
45
+ def remove
46
+ @client.remove_webhook(self)
47
+ end
48
+
49
+ def self.list_path
50
+ "v1/webhooks"
51
+ end
52
+
53
+ def self.create_path
54
+ "v1/webhooks"
55
+ end
56
+
57
+ def path
58
+ "/v1/webhooks/#{id}"
59
+ end
60
+ end
61
+ end
62
+
data/lib/particle.rb CHANGED
@@ -11,6 +11,25 @@ module Particle
11
11
  @client = Particle::Client.new(options)
12
12
  end
13
13
 
14
+ # Authenticate with Particle and start using the new token as the
15
+ # global token
16
+ #
17
+ # Delegates actual functionality to the client.
18
+ #
19
+ # @param username [String] The username (email) used to log in to
20
+ # the Particle Cloud API
21
+ # @param password [String] The password used to log in to
22
+ # the Particle Cloud API
23
+ # @param options [Hash] Additional Particle Cloud API options to
24
+ # create the token.
25
+ # @return [Token] The token object
26
+ # @see {Particle::Client::Tokens#login}
27
+ def login(username, password, options = {})
28
+ token = client.login(username, password, options)
29
+ self.access_token = token.access_token
30
+ token
31
+ end
32
+
14
33
  private
15
34
 
16
35
  def respond_to_missing?(method_name, include_private = false)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: particlerb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Julien Vanier
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-06-25 00:00:00.000000000 Z
11
+ date: 2015-06-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sawyer
@@ -149,13 +149,20 @@ files:
149
149
  - lib/particle.rb
150
150
  - lib/particle/client.rb
151
151
  - lib/particle/client/devices.rb
152
+ - lib/particle/client/publish.rb
153
+ - lib/particle/client/tokens.rb
154
+ - lib/particle/client/webhooks.rb
152
155
  - lib/particle/configurable.rb
153
156
  - lib/particle/connection.rb
154
157
  - lib/particle/default.rb
155
158
  - lib/particle/device.rb
156
159
  - lib/particle/error.rb
160
+ - lib/particle/event.rb
161
+ - lib/particle/model.rb
157
162
  - lib/particle/response/raise_error.rb
163
+ - lib/particle/token.rb
158
164
  - lib/particle/version.rb
165
+ - lib/particle/webhook.rb
159
166
  - lib/particlerb.rb
160
167
  - particlerb.gemspec
161
168
  homepage: https://github.com/monkbroc/particlerb