Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Added datapoint casting to datastream

  • Loading branch information...
commit 4477ea1c8576380dd3c79eb745de0e823caedf55 1 parent 78a19fa
@jwtd authored
View
123 README.md
@@ -1,15 +1,46 @@
xively-rb-connector
===================
-Ruby gem that provides an interface to Xively by extending xively-rb with convenience functions such Device.find_by_id, a datastream compression (only saves datapoints when value changes), a datapoint recording buffer, etc.
+xively-rb-connector is a ruby gem that provides an interface to [Xively](https://xively.com). It extends Sam Mulube's
+excellent [xively-rb](https://github.com/xively/xively-rb) gem. This gem adds convenience functions such as find_by_id
+lookup functions, datastream compression (only saves datapoints when value changes), a datapoint recording buffer, etc.
+[Xively](https://xively.com/whats_xively/) is a public cloud specifically built for the "Internet of Things". With their
+platform, developers can connect physical devices, that produce one or more datastreams, to a managed data store. The
+device's details and datastreams are accessible via key-based access to any service or application that has access to the
+web. Xively provides a fantastic development portal and prototyping accounts are free.
+
+## Requirements
+
+* Ruby 1.9.3 or higher
+* A [Xively account](https://xively.com/signup)
+
+## Contact, feedback and bugs
+
+Please file bugs / issues and feature requests on the [issue tracker](https://github.com/jwtd/xively-rb-connector/issues)
+
+## Install
+
+```
+gem install xively-rb-connector
+```
+
+## Examples
```ruby
require 'xively-rb-connector'
-d = XivelyConnector.find_device_by_id('123456789', 'ACCOUNT-OR-DEVICE-API-KEY-HERE')
+# Xively provides a master api-key and device specific keys. To my knowledge, either can be used here.
+my_api_key = 'XIVELY-ACCOUNT-OR-DEVICE-API-KEY-HERE'
+
+# Each device on Xively gets thier own ID, which is exposed via thier REST API as a "feed"
+feed_id = '123456789'
+# Find your device on Xively by its feed_id
+d = XivelyConnector.find_device_by_id(feed_id, my_api_key)
+
+# Access details about the device
d.id # 123456789
d.feed # https://api.xively.com/v2/feeds/123456789.json
d.auto_feed_url # https://api.xively.com/v2/feeds/123456789.json
@@ -30,9 +61,8 @@ d.is_private? # true
d.status # live
d.is_frozen? # false
-# Access location data
+# Access location data directly
d.has_location? # true
-d.location #<OpenStruct name="The location name on xively.com", latitude=35.12343454, longitude=-78.12343456, elevation="354 feet", exposure=nil, disposition=nil, waypoints=nil, domain="physical">
d.location_name # The location name on xively.com
d.location_domain # physical
d.location_lon # -78.12343456
@@ -42,34 +72,71 @@ d.location_exposure
d.location_disposition
d.location_waypoints
+# Or get a structure that has all the location details
+l = d.location #<OpenStruct name="The location name on xively.com", latitude=35.12343454, longitude=-78.12343456, elevation="354 feet", exposure=nil, disposition=nil, waypoints=nil, domain="physical">
+l.name # The location name on xively.com
+l.domain # physical
+l.longitude # -78.12343456
+l.latitude # 35.12343454
+l.elevation # 354 feet
+l.exposure
+l.disposition
+l.waypoints
+
# Examine datastreams
-d.datastream_ids ["Amps", "Propane", "Volts", "Watts", "Well"]
-d.datastream_values ["Amps in Amps (A) = 0", "Propane in Cubic Feet (cft) = 0", "Volts in Volts (V) = 9", "Watts in Watts (W) = 0", "Well in Cubic Feet (cft) = 0"]
-d.has_channel?('Volts') true
+d.datastream_ids # ["Amperage", "Propane", "Voltage", "Power", "Well"]
+d.datastream_values # ["Amperage in Amps (A) = 0", "Propane in Cubic Feet (cft) = 0", "Voltage in Volts (V) = 9", "Power in Watts (W) = 0", "Well in Cubic Feet (cft) = 0"]
+d.has_channel?('Voltage') # true
+
+# Access datastreams by channel name using bracket syntax
+d['Voltage'] # <XivelyConnector::Datastream:0x007ff62a137b80>
+d['Voltage'].current_value # 9
-# Access datastreams by channel name
-d['Volts'] #<XivelyConnector::Datastream:0x007ff62a137b80>
-d['Volts'].current_value 9
ds = d['Volts']
-ds.id Volts
-ds.current_value 9
-ds.tags Power
-ds.min_value 0.0
-ds.max_value 25.0
-ds.unit_label Volts
-ds.unit_symbol V
-
-# Queue new datapoints using the shift operator
-ds.datapoints.size 0
-ds << Xively::Datapoint.new(:at => Time.now(), :value => "10")
-ds << Xively::Datapoint.new(:at => Time.now(), :value => "15")
-ds << Xively::Datapoint.new(:at => Time.now(), :value => "25")
-ds.datapoints.size 3
+ds.id # Voltage
+ds.unit_label # Volts
+ds.unit_symbol # V
+ds.current_value # 9
+ds.tags # Power
+ds.min_value # 0.0
+ds.max_value # 25.0
+
+# Setup my datastream buffer
+ds.only_save_changes = true # Will only queue a datapoint if its value is different from the previous datapoint's which is also the current_value
+ds.datapoint_buffer_size = 60 # Will auto-save to feed when 60 points are queued
+ds.only_save_changes # true
+ds.only_saves_changes? # true
+ds.datapoint_buffer_size # 60
+
+# Queue new datapoints in a number of ways using the shift operator
+# BigDecimal is used for value comparison so "10" == 10 == 10.0
+
+ds.datapoints.size # 0
+ds << Xively::Datapoint.new(:value => "10", :at => Time.now,())
+ds << {:at=>':at => Time.now(), :value => "10"}
+ds << "10"
+ds << 10
+ds << 10.0
+ds << 11
+
+# If ds.only_save_changes is true, the commands above only result in two datapoints being queued (because the only unique values recorded were 10 and 11)
+ds.datapoints.size # 2
# Save datapoints to xively.com
-ds.only_saves_changes? true # Will only queue a datapoint if its value is different from the previous datapoint's which is also the current_value
-ds.datapoint_buffer_size 60 # Will auto-save to feed when 60 points are added
ds.save_datapoints
-ds.datapoints.size 0
+ds.datapoints.size # 0
+
+```
+
+## Resources
+
+* [Free Xively Developer Account](https://xively.com/signup)
+* [xively-rb](https://github.com/xively/xively-rb)
+* [xively-js](http://xively.github.io/xively-js) is a javascript lib for viewing and charting Xively data
+
+## Special Thanks
+
+* Xively - for an awesome data platform
+* Sam Mulube - for xively-rb
+* Ian Duggan - for introducing me to ruby
-```
View
37 lib/xively-rb-connector/datastream.rb
@@ -43,14 +43,17 @@ def initialize(options)
end
+ # Add a question style accessor to only_save_changes attribute
def only_saves_changes?
only_save_changes
end
# Have shift operator load the datapoint into the datastream's datapoints array
- # If only_save_changes is true, ignore datapoints whose value is the same as the current value
- # If the datapoints array has exceeded the datapoint_buffer_size, send them to Xively
- def <<(datapoint)
+ def <<(measurement)
+ # Make sure the value provided is a datapoint
+ datapoint = cast_to_datapoint(measurement)
+
+ # If only_save_changes is true, ignore datapoints whose value is the same as the current value
if only_save_changes and BigDecimal.new(datapoint.value) == BigDecimal.new(current_value)
@logger.debug "Ignoring datapoint from #{datapoint.at} because value did not change from #{current_value}"
else
@@ -58,7 +61,23 @@ def <<(datapoint)
datapoints << datapoint
@logger.debug "Queuing datapoint from #{datapoint.at} with value #{current_value}"
end
- save_datapoints if datapoints.size >= @datapoint_buffer_size
+
+ # See if the buffer is full
+ check_datapoints_buffer
+ end
+
+ # Converts a measurement to a Datapoint
+ def cast_to_datapoint(measurement, at=Time.now())
+ @logger.debug "cast_to_datapoint(#{measurement.inspect})"
+ if measurement.is_a?(Xively::Datapoint)
+ return measurement
+ elsif measurement.is_a?(Hash)
+ raise "The datapoint hash does not contain :at" unless measurement[:at]
+ raise "The datapoint hash does not contain :value" unless measurement[:value]
+ return Xively::Datapoint.new(measurement)
+ else
+ return Xively::Datapoint.new(:at => at, :value => measurement.to_s)
+ end
end
# Send the queued datapoints array to Xively
@@ -66,8 +85,9 @@ def save_datapoints
@logger.debug "Saving #{datapoints.size} datapoints to the #{id} datastream"
response = XivelyConnector.connection.post("/v2/feeds/#{device.id}/datastreams/#{id}/datapoints",
:body => {:datapoints => datapoints}.to_json)
+ # If the response succeeded, clear the datapoint buffer and return the response object
if response.success?
- clear_datapoints
+ clear_datapoints_buffer
response
else
logger.error response.response
@@ -75,8 +95,13 @@ def save_datapoints
end
end
+ # If the datapoints array has exceeded the datapoint_buffer_size, send them to Xively
+ def check_datapoints_buffer
+ save_datapoints if datapoints.size >= @datapoint_buffer_size
+ end
+
# Resets the datapoints
- def clear_datapoints
+ def clear_datapoints_buffer
@datapoints = []
end
View
21 xively-rb-connector.gemspec
@@ -8,8 +8,17 @@ Gem::Specification.new do |spec|
spec.version = XivelyConnector::VERSION::STRING
spec.authors = ["Jordan Duggan"]
spec.email = ["Jordan.Duggan@gmail.com"]
- spec.description = %q{Ruby gem that provides an interface to Xively by extending xively-rb with convenience functions such Device.find_by_id, a datastream compression (only saves datapoints when value changes), a datapoint recording buffer, etc.}
- spec.summary = %q{Ruby gem that provides an interface to Xively by extending xively-rb with convenience functions such Device.find_by_id, a datastream compression (only saves datapoints when value changes), a datapoint recording buffer, etc.}
+
+ spec.summary = %q{Ruby gem that provides a high level interface to Xively}
+ spec.description = %q{xively-rb-connector is a ruby gem that provides an interface to Xively (https://xively.com). It extends Sam Mulube's
+excellent xively-rb (https://github.com/xively/xively-rb) gem. The xively-rb-connector gem adds convenience functions such as find_by_id
+lookup functions, datastream compression (only saves datapoints when value changes), a datapoint recording buffer, etc.
+
+Xively (https://xively.com/whats_xively) is a public cloud specifically built for the "Internet of Things". With their
+platform, developers can connect physical devices, that produce one or more datastreams, to a managed data store. The
+device's details and datastreams are accessible via key-based access to any service or application that has access to the
+web. Xively provides a fantastic development portal and prototyping accounts are free.}
+
spec.homepage = "https://github.com/jwtd/xively-rb-connector"
spec.license = "MIT"
@@ -20,11 +29,11 @@ Gem::Specification.new do |spec|
# Development dependencies
spec.add_development_dependency "bundler", "~> 1.3"
- spec.add_development_dependency "rake"
+ spec.add_development_dependency "rake", "~> 10.2"
# Runtime dependencies
- spec.add_runtime_dependency "log4r"
- spec.add_runtime_dependency "xively-rb"
- spec.add_runtime_dependency "bigdecimal"
+ spec.add_runtime_dependency "log4r", "~> 1.1"
+ spec.add_runtime_dependency "xively-rb", "~> 0.2"
+ spec.add_runtime_dependency "bigdecimal", "~> 1.2"
end
Please sign in to comment.
Something went wrong with that request. Please try again.