device-cloud 0.2.0 → 0.3.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/device-cloud.gemspec CHANGED
@@ -32,7 +32,7 @@ Gem::Specification.new do |spec|
32
32
  spec.add_development_dependency "guard-bundler"
33
33
  spec.add_development_dependency "libnotify"
34
34
  spec.add_development_dependency "coveralls"
35
-
35
+ spec.add_development_dependency "timecop"
36
36
 
37
37
 
38
38
  end
@@ -23,19 +23,19 @@ module DeviceCloud
23
23
  end
24
24
 
25
25
  def get(path, *args)
26
- RestClient.get base_url + path, args
26
+ RestClient.get base_url + path, *args
27
27
  end
28
28
 
29
29
  def put(path, *args)
30
- RestClient.put base_url + path, args
30
+ RestClient.put base_url + path, *args
31
31
  end
32
32
 
33
33
  def post(path, *args)
34
- RestClient.post base_url + path, args
34
+ RestClient.post base_url + path, *args
35
35
  end
36
36
 
37
37
  def delete(path, *args)
38
- RestClient.delete base_url + path, args
38
+ RestClient.delete base_url + path, *args
39
39
  end
40
40
 
41
41
  def base_url
@@ -8,12 +8,16 @@ module DeviceCloud
8
8
  attr_accessor :username, :password, :host, :protocol
9
9
 
10
10
  def initialize(args)
11
- args = Hash[*args.map { |k, v| [k.to_sym, v] }.flatten]
12
- @username = args[:username] || DEFAULT_USERNAME
13
- @password = args[:password] || DEFAULT_PASSWORD
14
- @host = args[:host] || DEFAULT_HOST
15
- @protocol = args[:protocol] || DEFAULT_PROTOCOL
11
+ args = Hash[*args.map { |k, v| [k.to_s, v] }.flatten] unless args.nil?
12
+ init_with args
16
13
  end
17
14
 
15
+ # YAML Initializer
16
+ def init_with(args)
17
+ @username = args["username"] || DEFAULT_USERNAME
18
+ @password = args["password"] || DEFAULT_PASSWORD
19
+ @host = args["host"] || DEFAULT_HOST
20
+ @protocol = args["protocol"] || DEFAULT_PROTOCOL
21
+ end
18
22
  end
19
23
  end
@@ -41,7 +41,11 @@ module DeviceCloud
41
41
  end
42
42
 
43
43
  def mac
44
- stream_id_parse[2].to_i(16)
44
+ path.to_i(16)
45
+ end
46
+
47
+ def path
48
+ stream_id_parse[2]
45
49
  end
46
50
 
47
51
  def name
@@ -0,0 +1,52 @@
1
+ require 'device_cloud'
2
+
3
+ module DeviceCloud
4
+ class DataStreamClient
5
+ attr_accessor :client, :ttl
6
+
7
+ attr_reader :last_updated, :raw_cache, :parsed_cache
8
+
9
+ def initialize(config, client = nil)
10
+ @client = client || Client.new(config)
11
+ @ttl = config["ttl"] || 60
12
+ @last_updated = nil
13
+ end
14
+
15
+ # match the stream_id against regex
16
+ def match(regex)
17
+ cache.select do |stream|
18
+ stream.stream_id.match regex
19
+ end
20
+ end
21
+
22
+ def devices
23
+ cache.map do |stream|
24
+ {
25
+ device_id: stream.device_id,
26
+ path: stream.path
27
+ }
28
+ end.uniq
29
+ end
30
+
31
+ def invalidate
32
+ @last_updated = nil
33
+ end
34
+
35
+ def valid?
36
+ !@last_updated.nil? and (Time.now - @ttl) < @last_updated
37
+ end
38
+
39
+ def cache
40
+ if !valid? || parsed_cache.nil?
41
+ # We need to update the cache
42
+
43
+ # Get all streams, and we will parse it out using xpath.
44
+ @raw_cache = client.get DataStream::RESOURCE_PATH
45
+ @parsed_cache = DataStream.parse raw_cache
46
+ #get the thing
47
+ @last_updated = Time.now
48
+ end
49
+ parsed_cache
50
+ end
51
+ end
52
+ end
@@ -1,3 +1,3 @@
1
1
  module DeviceCloud
2
- VERSION = "0.2.0"
2
+ VERSION = "0.3.0"
3
3
  end
data/lib/device_cloud.rb CHANGED
@@ -3,6 +3,7 @@ require 'device_cloud/config'
3
3
  require 'device_cloud/client'
4
4
  require 'device_cloud/device_core'
5
5
  require 'device_cloud/data_stream'
6
+ require 'device_cloud/data_stream_client'
6
7
  require 'device_cloud/data_point'
7
8
  require 'device_cloud/result'
8
- require 'device_cloud/monitor'
9
+ require 'device_cloud/monitor'
@@ -1,7 +1,7 @@
1
1
  require "spec_helper"
2
2
 
3
3
  describe DeviceCloud::Client do
4
- subject do
4
+ subject(:client) do
5
5
  DeviceCloud::Client.new(:username => username, :password => password, :host => host, :protocol => protocol)
6
6
  end
7
7
  let(:username) { "test" }
@@ -11,10 +11,34 @@ describe DeviceCloud::Client do
11
11
 
12
12
 
13
13
  it 'will generate a base_url using the configuration' do
14
- subject.base_url.should == "#{protocol}://#{username}:#{password}@#{host}"
15
- subject.config.protocol = "http"
16
- subject.base_url.should == "http://#{username}:#{password}@#{host}"
17
- subject.config.host = "google.com"
18
- subject.base_url.should == "http://#{username}:#{password}@google.com"
14
+ client.base_url.should == "#{protocol}://#{username}:#{password}@#{host}"
15
+ client.config.protocol = "http"
16
+ client.base_url.should == "http://#{username}:#{password}@#{host}"
17
+ client.config.host = "google.com"
18
+ client.base_url.should == "http://#{username}:#{password}@google.com"
19
19
  end
20
- end
20
+
21
+ describe "#devices" do
22
+ let(:result) { "Device Core XML" }
23
+ before :each do
24
+ client.stub(:get => result)
25
+ DeviceCloud::DeviceCore.stub(:parse)
26
+ end
27
+
28
+ context "No parameters" do
29
+ it "will use the correct url" do
30
+ client.devices("*")
31
+ expect(client).to have_received(:get).with("/ws/DeviceCore/*?")
32
+ expect(DeviceCloud::DeviceCore).to have_received(:parse).with(result)
33
+ end
34
+ end
35
+
36
+ context "Filtering with parameters" do
37
+ it "will use the correct url" do
38
+ client.devices("*", "grpPath" => "IVX", "test" => "true")
39
+ expect(client).to have_received(:get).with("/ws/DeviceCore/*?grpPath=IVX&test=true")
40
+ expect(DeviceCloud::DeviceCore).to have_received(:parse).with(result)
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,282 @@
1
+ require 'spec_helper'
2
+
3
+ require 'timecop'
4
+
5
+ describe DeviceCloud::DataStreamClient do
6
+ subject(:data_stream_client) { DeviceCloud::DataStreamClient.new config, client }
7
+ let(:client) { double("DeviceCloud::Client", :get => xml) }
8
+ let(:config) { {"ttl" => 55} }
9
+
10
+ let(:xml) do
11
+ <<-XML
12
+ <?xml version="1.0" encoding="ISO-8859-1"?>
13
+ <result>
14
+ <resultSize>8</resultSize>
15
+ <requestedSize>1000</requestedSize>
16
+ <pageCursor>76cab9ad-5-ebd5ccac</pageCursor>
17
+ <DataStream>
18
+ <cstId>5940</cstId>
19
+ <streamId>dia/channel/00000000-00000000-00409DFF-FF725771/0013a20040a52e1d/distance</streamId>
20
+ <dataType>DOUBLE</dataType>
21
+ <forwardTo/>
22
+ <currentValue>
23
+ <id>5101f920-53b4-11e3-8b51-bc764e113426</id>
24
+ <timestamp>1385151966954</timestamp>
25
+ <serverTimestamp>1385151968249</serverTimestamp>
26
+ <data>44.2</data>
27
+ <description/>
28
+ <quality>0</quality>
29
+ </currentValue>
30
+ <description/>
31
+ <units>in</units>
32
+ <dataTtl>2678400</dataTtl>
33
+ <rollupTtl>8035200</rollupTtl>
34
+ </DataStream>
35
+ <DataStream>
36
+ <cstId>5940</cstId>
37
+ <streamId>dia/channel/00000000-00000000-00409DFF-FF725771/0013a2004063d301/distance</streamId>
38
+ <dataType>DOUBLE</dataType>
39
+ <forwardTo/>
40
+ <currentValue>
41
+ <id>510c337d-53b4-11e3-8b51-bc764e113426</id>
42
+ <timestamp>1385151967021</timestamp>
43
+ <serverTimestamp>1385151968488</serverTimestamp>
44
+ <data>0.0</data>
45
+ <description/>
46
+ <quality>0</quality>
47
+ </currentValue>
48
+ <description/>
49
+ <units>in</units>
50
+ <dataTtl>2678400</dataTtl>
51
+ <rollupTtl>8035200</rollupTtl>
52
+ </DataStream>
53
+ <DataStream>
54
+ <cstId>5940</cstId>
55
+ <streamId>dia/channel/00000000-00000000-00409DFF-FF725771/0013a200408cb965/distance</streamId>
56
+ <dataType>DOUBLE</dataType>
57
+ <forwardTo/>
58
+ <currentValue>
59
+ <id>50e8a4e8-53b4-11e3-8b51-bc764e113426</id>
60
+ <timestamp>1385151966788</timestamp>
61
+ <serverTimestamp>1385151968064</serverTimestamp>
62
+ <data>0.0</data>
63
+ <description/>
64
+ <quality>0</quality>
65
+ </currentValue>
66
+ <description/>
67
+ <units>in</units>
68
+ <dataTtl>2678400</dataTtl>
69
+ <rollupTtl>8035200</rollupTtl>
70
+ </DataStream>
71
+ <DataStream>
72
+ <cstId>5940</cstId>
73
+ <streamId>dia/channel/00000000-00000000-00409DFF-FF725771/0013a20040a52b7a/distance</streamId>
74
+ <dataType>DOUBLE</dataType>
75
+ <forwardTo/>
76
+ <currentValue>
77
+ <id>50f1cc94-53b4-11e3-8b51-bc764e113426</id>
78
+ <timestamp>1385151966848</timestamp>
79
+ <serverTimestamp>1385151968068</serverTimestamp>
80
+ <data>0.0</data>
81
+ <description/>
82
+ <quality>0</quality>
83
+ </currentValue>
84
+ <description/>
85
+ <units>in</units>
86
+ <dataTtl>2678400</dataTtl>
87
+ <rollupTtl>8035200</rollupTtl>
88
+ </DataStream>
89
+ <DataStream>
90
+ <cstId>5940</cstId>
91
+ <streamId>dia/channel/00000000-00000000-00409DFF-FF725771/0013a20040a52e1d/temperature</streamId>
92
+ <dataType>DOUBLE</dataType>
93
+ <forwardTo/>
94
+ <currentValue>
95
+ <id>5101f920-53b4-11e3-8b51-bc764e113426</id>
96
+ <timestamp>1385151966954</timestamp>
97
+ <serverTimestamp>1385151968249</serverTimestamp>
98
+ <data>44.2</data>
99
+ <description/>
100
+ <quality>0</quality>
101
+ </currentValue>
102
+ <description/>
103
+ <units>in</units>
104
+ <dataTtl>2678400</dataTtl>
105
+ <rollupTtl>8035200</rollupTtl>
106
+ </DataStream>
107
+ <DataStream>
108
+ <cstId>5940</cstId>
109
+ <streamId>dia/channel/00000000-00000000-00409DFF-FF725771/0013a2004063d301/temperature</streamId>
110
+ <dataType>DOUBLE</dataType>
111
+ <forwardTo/>
112
+ <currentValue>
113
+ <id>510c337d-53b4-11e3-8b51-bc764e113426</id>
114
+ <timestamp>1385151967021</timestamp>
115
+ <serverTimestamp>1385151968488</serverTimestamp>
116
+ <data>21.2</data>
117
+ <description/>
118
+ <quality>0</quality>
119
+ </currentValue>
120
+ <description/>
121
+ <units>in</units>
122
+ <dataTtl>2678400</dataTtl>
123
+ <rollupTtl>8035200</rollupTtl>
124
+ </DataStream>
125
+ <DataStream>
126
+ <cstId>5940</cstId>
127
+ <streamId>dia/channel/00000000-00000000-00409DFF-FF725771/0013a200408cb965/temperature</streamId>
128
+ <dataType>DOUBLE</dataType>
129
+ <forwardTo/>
130
+ <currentValue>
131
+ <id>50e8a4e8-53b4-11e3-8b51-bc764e113426</id>
132
+ <timestamp>1385151966788</timestamp>
133
+ <serverTimestamp>1385151968064</serverTimestamp>
134
+ <data>20.0</data>
135
+ <description/>
136
+ <quality>0</quality>
137
+ </currentValue>
138
+ <description/>
139
+ <units>in</units>
140
+ <dataTtl>2678400</dataTtl>
141
+ <rollupTtl>8035200</rollupTtl>
142
+ </DataStream>
143
+ <DataStream>
144
+ <cstId>5940</cstId>
145
+ <streamId>dia/channel/00000000-00000000-00409DFF-FF725771/0013a20040a52b7a/temperature</streamId>
146
+ <dataType>DOUBLE</dataType>
147
+ <forwardTo/>
148
+ <currentValue>
149
+ <id>50f1cc94-53b4-11e3-8b51-bc764e113426</id>
150
+ <timestamp>1385151966848</timestamp>
151
+ <serverTimestamp>1385151968068</serverTimestamp>
152
+ <data>32.2</data>
153
+ <description/>
154
+ <quality>0</quality>
155
+ </currentValue>
156
+ <description/>
157
+ <units>in</units>
158
+ <dataTtl>2678400</dataTtl>
159
+ <rollupTtl>8035200</rollupTtl>
160
+ </DataStream>
161
+ </result>
162
+ XML
163
+ end
164
+
165
+
166
+ describe "#valid?" do
167
+ before :each do
168
+ Timecop.freeze
169
+ end
170
+
171
+ context("The cache has not been updated") do
172
+ it "will return false" do
173
+ expect(data_stream_client.valid?).to eql false
174
+ end
175
+ end
176
+
177
+ context("A request has recently been made") do
178
+ before(:each) do
179
+ data_stream_client.cache
180
+ Timecop.travel Time.now + 10
181
+ end
182
+
183
+ it "will return true" do
184
+ expect(data_stream_client.valid?).to eql true
185
+ end
186
+ end
187
+
188
+ after(:each) do
189
+ Timecop.return
190
+ end
191
+ end
192
+
193
+ describe "#devices" do
194
+ it "will return a data for every (device_id)/(path)/..." do
195
+
196
+ device_list = [{device_id: "00000000-00000000-00409DFF-FF725771", path: "0013a20040a52e1d"},
197
+ {device_id: "00000000-00000000-00409DFF-FF725771", path: "0013a2004063d301"},
198
+ {device_id: "00000000-00000000-00409DFF-FF725771", path: "0013a200408cb965"},
199
+ {device_id: "00000000-00000000-00409DFF-FF725771", path: "0013a20040a52b7a"}]
200
+
201
+
202
+ expect(data_stream_client.devices).to eql device_list
203
+ end
204
+ end
205
+
206
+ describe "#match" do
207
+ context "when the streams requested exit" do
208
+ it "returns a datastream object for each matched stream" do
209
+ streams = data_stream_client.match(".*/distance")
210
+ expect(streams.count).to eql 4
211
+ streams.each do |stream|
212
+ expect(stream.name).to eql "distance"
213
+ end
214
+ end
215
+ end
216
+
217
+ context "the requested stream does not exist" do
218
+ it "returns an empty array" do
219
+ expect(data_stream_client.match("foo")).to be_empty
220
+ end
221
+ end
222
+ end
223
+
224
+
225
+ describe "#invalidate" do
226
+ context "the cache is valid" do
227
+ before :each do
228
+ Timecop.freeze
229
+ data_stream_client.cache
230
+ end
231
+
232
+ after :each do
233
+ Timecop.return
234
+ end
235
+
236
+ it "sets last_updated to nil" do
237
+ expect { data_stream_client.invalidate }.to change { data_stream_client.last_updated }.from(Time.now).to nil
238
+ end
239
+ end
240
+ end
241
+
242
+ describe "#cache" do
243
+ let(:stream) { double("DeviceCloud::DataStream") }
244
+ before :each do
245
+ DeviceCloud::DataStream.stub(:parse => [stream])
246
+ Timecop.freeze
247
+ end
248
+
249
+ context "The cache is invalid" do
250
+ it "will update the cache age" do
251
+ expect { data_stream_client.cache }.to change { data_stream_client.last_updated }.to Time.now
252
+ end
253
+
254
+ it "will set the raw cache to the request xml" do
255
+ expect { data_stream_client.cache }.to change { data_stream_client.raw_cache }.to xml
256
+ end
257
+
258
+ it "will return the cache parsed as an array DataStreams" do
259
+ expect(data_stream_client.cache).to eql [stream]
260
+ expect(DeviceCloud::DataStream).to have_received(:parse).with(xml)
261
+ end
262
+ end
263
+
264
+ context "The cache is valid" do
265
+ before :each do
266
+ data_stream_client.stub(:valid? => true, :parsed_cache => [stream])
267
+ end
268
+
269
+ it "will only return the current cache value" do
270
+ expect(data_stream_client.cache).to eql [stream]
271
+ expect(DeviceCloud::DataStream).not_to have_received(:parse)
272
+ end
273
+ end
274
+
275
+ after :each do
276
+ Timecop.return
277
+ end
278
+ end
279
+
280
+ let(:serialized) { "--- !ruby/object:DeviceCloud::DataStreamCache \nttl: 33" }
281
+
282
+ end
@@ -135,6 +135,11 @@ describe DeviceCloud::DataStream do
135
135
  end
136
136
  end
137
137
 
138
+ describe "#path" do
139
+ it "returns the path of the datastream, which is the part of the streamId between the stream name and device_id" do
140
+ expect(data_stream.path).to eql "0013a20040a52e1d"
141
+ end
142
+ end
138
143
  describe "#mac" do
139
144
  it "returns the sensor mac from the device id and converts it to an integer" do
140
145
  expect(data_stream.mac).to eql "0013a20040a52e1d".to_i(16)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: device-cloud
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-01-15 00:00:00.000000000 Z
12
+ date: 2014-02-07 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: nokogiri
@@ -219,6 +219,22 @@ dependencies:
219
219
  - - ! '>='
220
220
  - !ruby/object:Gem::Version
221
221
  version: '0'
222
+ - !ruby/object:Gem::Dependency
223
+ name: timecop
224
+ requirement: !ruby/object:Gem::Requirement
225
+ none: false
226
+ requirements:
227
+ - - ! '>='
228
+ - !ruby/object:Gem::Version
229
+ version: '0'
230
+ type: :development
231
+ prerelease: false
232
+ version_requirements: !ruby/object:Gem::Requirement
233
+ none: false
234
+ requirements:
235
+ - - ! '>='
236
+ - !ruby/object:Gem::Version
237
+ version: '0'
222
238
  description: REST Wrapper for Etherios Devicecloud
223
239
  email:
224
240
  - eric@clean-logix.com
@@ -239,6 +255,7 @@ files:
239
255
  - lib/device_cloud/config.rb
240
256
  - lib/device_cloud/data_point.rb
241
257
  - lib/device_cloud/data_stream.rb
258
+ - lib/device_cloud/data_stream_client.rb
242
259
  - lib/device_cloud/device_core.rb
243
260
  - lib/device_cloud/monitor.rb
244
261
  - lib/device_cloud/result.rb
@@ -246,6 +263,7 @@ files:
246
263
  - spec/device_cloud/client_spec.rb
247
264
  - spec/device_cloud/config_spec.rb
248
265
  - spec/device_cloud/data_point_spec.rb
266
+ - spec/device_cloud/data_stream_client_spec.rb
249
267
  - spec/device_cloud/data_stream_spec.rb
250
268
  - spec/device_cloud/device_core_spec.rb
251
269
  - spec/device_cloud/monitor_spec.rb
@@ -280,6 +298,7 @@ test_files:
280
298
  - spec/device_cloud/client_spec.rb
281
299
  - spec/device_cloud/config_spec.rb
282
300
  - spec/device_cloud/data_point_spec.rb
301
+ - spec/device_cloud/data_stream_client_spec.rb
283
302
  - spec/device_cloud/data_stream_spec.rb
284
303
  - spec/device_cloud/device_core_spec.rb
285
304
  - spec/device_cloud/monitor_spec.rb