Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 10 additions & 8 deletions device_cloud.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,24 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
require 'device_cloud/version'

Gem::Specification.new do |spec|
spec.name = "device_cloud"
spec.name = 'device_cloud'
spec.version = DeviceCloud::VERSION
spec.authors = ["Erik Straub"]
spec.email = ["erik@madgloryint.com"]
spec.authors = ['Erik Straub']
spec.email = ['erik@madgloryint.com']
spec.description = %q{A Ruby wrapper for the Etherios Device Cloud}
spec.summary = %q{A Ruby wrapper for the Etherios Device Cloud}
spec.homepage = "http://github.com/madgloryint/device_cloud"
spec.license = "MIT"
spec.homepage = 'http://github.com/madgloryint/device_cloud'
spec.license = 'MIT'

spec.files = `git ls-files`.split($/)
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
spec.require_paths = ["lib"]
spec.require_paths = ['lib']

spec.add_development_dependency "bundler", "~> 1.3"
spec.add_development_dependency "rake"
spec.add_dependency 'nori', '~> 2.3'

spec.add_development_dependency 'bundler', '~> 1.3'
spec.add_development_dependency 'rake'
spec.add_development_dependency 'rspec'
spec.add_development_dependency 'webmock'
spec.add_development_dependency 'pry'
Expand Down
5 changes: 5 additions & 0 deletions lib/device_cloud.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
require 'device_cloud/configuration'
require 'device_cloud/utils'
require 'device_cloud/version'
require 'device_cloud/alarm'
require 'device_cloud/device_disconnect_alarm'
require 'device_cloud/alarm_template'
require 'device_cloud/group'
require 'device_cloud/monitor'
require 'device_cloud/push_notification'
require 'device_cloud/push_notification/base_notification'
Expand All @@ -11,6 +15,7 @@
require 'device_cloud/push_notification/message/file_data'
require 'device_cloud/request'
require 'device_cloud/response'
require 'nori'

module DeviceCloud
extend Configuration
Expand Down
173 changes: 173 additions & 0 deletions lib/device_cloud/alarm.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
module DeviceCloud
class Alarm

attr_accessor :almId, :cstId, :almtId, :grpId, :almName, :almDescription, :almScopeConfig, :almRuleConfig
attr_reader :error, :almEnabled, :almPriority

class << self
def all
response = DeviceCloud::Request.new(path: '/ws/Alarm').get
alarms = response.to_hash_from_xml

return [] unless response.code == '200' && alarms['result']['resultSize'].to_i > 0

if alarms['result']['resultSize'].to_i == 1
[initialize_proper_alarm_type(alarms['result']['Alarm'])]
else
alarms['result']['Alarm'].map { |alarm|
initialize_proper_alarm_type(alarm)
}
end
end

def find(id)
response = DeviceCloud::Request.new(path: "/ws/Alarm/#{id}").get
alarms = response.to_hash_from_xml

return nil unless response.code == '200' && alarms['result']['resultSize'].to_i > 0

if alarms['result']['resultSize'].to_i == 1
initialize_proper_alarm_type(alarms['result']['Alarm'])
else
initialize_proper_alarm_type(alarms['result']['Alarm'].first)
end
end

protected
def initialize_proper_alarm_type(alarm)
case alarm['almtId']
when '2' then DeviceDisconnectAlarm.new(alarm)
else Alarm.new(alarm)
end
end
end

def initialize(attributes = {})
set_defaults

attributes.each do |name, value|
send("#{name}=", value)
end
end

def almEnabled=(value)
@almEnabled = !!value
end

def almPriority=(value)
raise DeviceCloud::Error, 'almPriority must be 0 (high), 1 (medium), or 2 (low)' unless [0,1,2].include?(value.to_i)
@almPriority = value.to_i
end

def persist!
remove_instance_variable '@error' if error
almId.nil? ? create : update
end

def destroy!
return false if almId.nil?

response = DeviceCloud::Request.new(path: "/ws/Alarm/#{almId}").delete

response.code == '200' ? true : false
end

def attributes
available_attributes.inject({}) do |memo, attr_name|
memo[attr_name] = send(attr_name) unless send(attr_name).nil?
memo
end
end

protected
def set_defaults
# no-op
end

def available_attributes
%w{
almtId
almName
almDescription
almPriority
almEnabled
grpId
}
end

def create
response = DeviceCloud::Request.new(path: '/ws/Alarm', body: to_xml).post
xml_result = response.to_hash_from_xml['result']

if response.code == '201'
self.almId = xml_result['location'].sub /Alarm\//, ''
return true
else
@error = xml_result['error']
return false
end
end

def update
response = DeviceCloud::Request.new(path: "/ws/Alarm/#{almId}", body: to_xml).put

if response.code == '200'
return true
else
@error = error_from_response_xml(response)
return false
end
end

def to_xml
xml = '<Alarm>'
attributes.each do |key,value|
xml << "<#{key}>#{value}</#{key}>"
end
xml << alarm_scope_config_xml
xml << alarm_rule_config_xml
xml << '</Alarm>'
end

# Method to set the Alarm's scope
#
# Example:
# <almScopeConfig>
# <ScopingOptions>
# <Scope name="Resource" value="Weather/USA/*/Minneapolis"/>
# </ScopingOptions>
# </almScopeConfig>
def alarm_scope_config_xml
raise NotImplementedError
end

# Method to set the Alarm's rules
#
# Example:
# <almRuleConfig>
# <Rules>
# <FireRule name="fireRule1">
# <Variable name="operator" value="&gt;"/>
# <Variable name="thresholdvalue" value="1"/>
# <Variable name="timeUnit" value="seconds"/>
# <Variable name="timeout" value="10"/>
# <Variable name="type" value="double"/>
# </FireRule>
# <ResetRule name="resetRule1">
# <Variable name="type" value="double"/>
# <Variable name="thresholdvalue" value="1"/>
# <Variable name="operator" value="&lt;="/>
# <Variable name="timeUnit" value="seconds"/>
# <Variable name="timeout" value="10"/>
# </ResetRule>
# </Rules>
# </almRuleConfig>
def alarm_rule_config_xml
raise NotImplementedError
end

def error_from_response_xml(response)
response.body.match(/<error>(.*)<\/error>/)[1]
end
end
end
38 changes: 38 additions & 0 deletions lib/device_cloud/alarm_template.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
module DeviceCloud
class AlarmTemplate

attr_reader :almtId, :almtName, :almtDescription, :grpId, :almtTopic, :almtScopeOptions, :almtRules, :almtResourceList

class << self
def all
response = DeviceCloud::Request.new(path: '/ws/AlarmTemplate').get
templates = response.to_hash_from_xml

return [] unless response.code == '200' && templates['result']['resultSize'].to_i > 0

if templates['result']['resultSize'].to_i == 1
[AlarmTemplate.new(templates['result']['AlarmTemplate'])]
else
templates['result']['AlarmTemplate'].map { |template|
AlarmTemplate.new template
}
end
end

def find(id)
response = DeviceCloud::Request.new(path: "/ws/AlarmTemplate/#{id}").get
templates = response.to_hash_from_xml

return nil unless response.code == '200' && templates['result']['resultSize'].to_i == 1

AlarmTemplate.new(templates['result']['AlarmTemplate'])
end
end

def initialize(attributes = {})
attributes.each do |name, value|
instance_variable_set("@#{name}", value)
end
end
end
end
14 changes: 14 additions & 0 deletions lib/device_cloud/configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -110,5 +110,19 @@ def password
def logger
@logger ||= Logger.new(STDOUT)
end

# DeviceCloud logger
#
# @return the DeviceCloud logger or set the default to stdout
def logger
@logger ||= Logger.new(STDOUT)
end

# DeviceCloud xml_parser
#
# @return the DeviceCloud xml_parser - default is Nori using rexml
def xml_parser
Nori.new(parser: :rexml)
end
end
end
86 changes: 86 additions & 0 deletions lib/device_cloud/device_disconnect_alarm.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
module DeviceCloud
class DeviceDisconnectAlarm < Alarm
attr_accessor :reconnectWindowDuration, :reset_on_reconnect, :device_id, :group
attr_reader :group

def group=(group_object)
raise DeviceCloud::Error, 'Must be a DeviceCloud::Group' unless group_object.is_a?(DeviceCloud::Group)

@group = group_object
self.grpId = group.grpId
end

def initialize(attributes = {})
super
load_group
load_device_id
self.almtId = 2
end

def persist!
raise DeviceCloud::Error, 'Must specify @group or @device_id.' unless group || device_id
super
end
private
def default_create_options
{
'reconnectWindowDuration' => '5',
'reset_on_reconnect' => true
}
end

def set_defaults
super
default_create_options.each do |k,v|
send("#{k}=",v)
end
end

def alarm_scope_config_xml
return '' if group.nil? && device_id.nil?
"<almScopeConfig><ScopingOptions>\n#{scope_xml}</ScopingOptions></almScopeConfig>\n"
end

def scope_xml
group.nil? ? device_scope_xml : group_scope_xml
end

def group_scope_xml
"<Scope name=\"Group\" value=\"#{group.grpPath}\" />"
end

def device_scope_xml
"<Scope name=\"Device\" value=\"#{device_id}\" />"
end

def alarm_rule_config_xml
xml = "<almRuleConfig><Rules>\n"
xml << fire_rule_xml
xml << reset_rule_xml
xml << "</Rules></almRuleConfig>\n"
end

def reset_rule_xml
xml = '<ResetRule name="resetRule1"'
xml << ' enabled="false"' unless reset_on_reconnect
xml << " />\n"
end

def fire_rule_xml
xml = '<FireRule name="fireRule1">'
xml << '<Variable name="reconnectWindowDuration" value="'
xml << reconnectWindowDuration
xml << "\" /></FireRule>\n"
end

def load_group
return if almScopeConfig.nil? || almScopeConfig['ScopingOptions']['Scope']['@name'] != 'Group'
@group ||= DeviceCloud::Group.find(grpId)
end

def load_device_id
return if almScopeConfig.nil? || almScopeConfig['ScopingOptions']['Scope']['@name'] != 'Device'
@device_id ||= almScopeConfig['ScopingOptions']['Scope']['@value']
end
end
end
Loading