wemote 0.2.2 → 0.2.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8fab169b7fb29b3ed90820cfa268951f6a88f28d
4
- data.tar.gz: cd0c3fd1971486865e170eae94cca933e1558070
3
+ metadata.gz: 50907f96c202b14aff7fbac722c9133a3c4860f5
4
+ data.tar.gz: 2fa839d4ce9819d5223f078b08464906556bcfb1
5
5
  SHA512:
6
- metadata.gz: f365c6b952fd03d3b38d53081ede3d21ac1d28a1c4568e0d0275d9f3ddc0732a0b8651fbf33a20c0aa43d9335b0d41449906df90f4902e74a064f2f08e304de1
7
- data.tar.gz: aafdae13551a09dfc8b4ce12336e6a3e3971add9667f7a61c5dd4b57353e5d49e4f69112d0a6945304852e00320d33ef89a2d3029006ae3decd2e42c053274e6
6
+ metadata.gz: 352264a9e37d2d4e3e54e1925b751e2d37adb277cfd7e6b818864afd3315fa0f332bd836242f5d2f7e8c1fecc6571761c214eac4126c9c6f1143e37236a8047f
7
+ data.tar.gz: c7a62b670905ff95356342c2886d76f61cc21e2384c0da60abff32fea4fb267b503faa7ac8482d208fb66151cf5e91ebf9523a6f2aac787addde5a39c3769c1e
@@ -2,7 +2,9 @@ require_relative './wemote/version'
2
2
 
3
3
  module Wemote
4
4
  require_relative './wemote/collection/switch'
5
+ require_relative './wemote/collection/insight'
5
6
  require_relative './wemote/switch'
7
+ require_relative './wemote/insight'
6
8
  require_relative './wemote/client'
7
9
  require_relative './wemote/xml'
8
10
 
@@ -0,0 +1,12 @@
1
+ module Wemote
2
+ module Collection
3
+
4
+ # This class provides an extension on the basic Array object, in order to
5
+ # facilitate group operations on a collection of Wemote::Switch instances.
6
+ class Insight < Switch
7
+
8
+ make :standby?
9
+
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,90 @@
1
+ require 'socket'
2
+ require 'ipaddr'
3
+ require 'timeout'
4
+ require 'ssdp'
5
+
6
+ module Wemote
7
+
8
+ # This class encapsulates an individual Wemo Insight. It provides methods for
9
+ # getting and setting the insight's state, as well as a {#toggle!} method for
10
+ # convenience. Finally, it provides the {#poll} method, which accepts a block
11
+ # to be executed any time the insight changes state.
12
+ class Insight < Switch
13
+
14
+ GET_HEADERS_POWER = {
15
+ "SOAPACTION" => '"urn:Belkin:service:insight:1#GetInsightParams"',
16
+ "Content-type" => 'text/xml; charset="utf-8"'
17
+ }
18
+
19
+ class << self
20
+
21
+ def device_type
22
+ 'urn:Belkin:device:insight:1'
23
+ end
24
+
25
+ # Returns all Insight detected on the local network
26
+ #
27
+ # @param [Boolean] refresh Refresh and redetect Insight
28
+ # @return [Array] all Insight on the network
29
+ def all(refresh=false)
30
+ @insights = nil if refresh
31
+ @insights ||= Wemote::Collection::Insight.new(discover)
32
+ end
33
+
34
+ end
35
+
36
+ # Turn the Insight on or off, based on its current state
37
+ def toggle!
38
+ on? or standby? ? off! : on!;
39
+ end
40
+
41
+ # Return whether the Insight is standby
42
+ #
43
+ # @return [Boolean]
44
+ def standby?
45
+ get_state == :standby;
46
+ end
47
+
48
+ def power
49
+ get_insight_params()[:power]
50
+ end
51
+
52
+ def energy
53
+ get_insight_params()[:energy]
54
+ end
55
+
56
+ def on_today
57
+ get_insight_params()[:on_today]
58
+ end
59
+
60
+ private
61
+
62
+ def get_state
63
+ case get_binary_state()
64
+ when '0'
65
+ :off
66
+ when '1'
67
+ :on
68
+ when '8'
69
+ :standby
70
+ end
71
+ end
72
+
73
+ def get_insight_params
74
+ response = begin
75
+ client.post("http://#{@host}:#{@port}/upnp/control/insight1",Wemote::XML.get_insight_params,GET_HEADERS_POWER)
76
+ rescue Exception
77
+ client.post("http://#{@host}:#{@port}/upnp/control/insight1",Wemote::XML.get_insight_params,GET_HEADERS_POWER)
78
+ end
79
+ params = response.body.match(/<InsightParams>(.*)<\/InsightParams>/)[1].split('|')
80
+ {
81
+ value: (params[0].to_i == 0 ? :off : :on),
82
+ energy: (params[8].to_i / 60000000.0).ceil,
83
+ power: (params[7].to_i / 1000.0).round,
84
+ on_today: (params[3].to_i / 60.0).floor
85
+ }
86
+ end
87
+
88
+
89
+ end
90
+ end
@@ -1,6 +1,7 @@
1
1
  require 'socket'
2
2
  require 'ipaddr'
3
3
  require 'timeout'
4
+ require 'ssdp'
4
5
 
5
6
  module Wemote
6
7
 
@@ -10,8 +11,6 @@ module Wemote
10
11
  # to be executed any time the switch changes state.
11
12
  class Switch
12
13
 
13
- GOOGLE_IP = "64.233.187.99"
14
-
15
14
  GET_HEADERS = {
16
15
  "SOAPACTION" => '"urn:Belkin:service:basicevent:1#GetBinaryState"',
17
16
  "Content-type" => 'text/xml; charset="utf-8"'
@@ -23,6 +22,11 @@ module Wemote
23
22
  }
24
23
 
25
24
  class << self
25
+
26
+ def device_type
27
+ 'urn:Belkin:device:controllee:1'
28
+ end
29
+
26
30
  # Returns all Switches detected on the local network
27
31
  #
28
32
  # @param [Boolean] refresh Refresh and redetect Switches
@@ -40,14 +44,15 @@ module Wemote
40
44
  all.detect{|s|s.name == name}
41
45
  end
42
46
 
43
- private
47
+ protected
44
48
 
45
49
  def discover
46
- ip = UDPSocket.open {|s| s.connect(GOOGLE_IP, 1); s.addr.last}
47
- `nmap -sP #{ip.split('.')[0..-2].join('.')}.* > /dev/null && arp -na | grep b4:75`.split("\n").map do |device|
48
- self.new(/\((\d+\.\d+\.\d+\.\d+)\)/.match(device)[1])
49
- end.reject{|device| device.instance_variable_get(:@port).nil? }
50
+ finder = SSDP::Consumer.new timeout: 3, first_only: false
51
+ finder.search(service: self.device_type).map do |device|
52
+ self.new(device[:address], device[:params]['LOCATION'].match(/:([0-9]{1,5})\//)[1])
53
+ end
50
54
  end
55
+
51
56
  end
52
57
 
53
58
  attr_accessor :name
@@ -57,24 +62,38 @@ module Wemote
57
62
  set_meta
58
63
  end
59
64
 
65
+ def device_type
66
+ 'urn:Belkin:device:controllee:1'
67
+ end
68
+
60
69
  # Turn the Switch on or off, based on its current state
61
- def toggle!; on? ? off! : on!; end
70
+ def toggle!
71
+ on? ? off! : on!
72
+ end
62
73
 
63
74
  # Turn the Switch off
64
- def off!; set_state(0); end
75
+ def off!
76
+ set_state(0)
77
+ end
65
78
 
66
79
  # Turn the Switch on
67
- def on!; set_state(1); end
80
+ def on!
81
+ set_state(1)
82
+ end
68
83
 
69
84
  # Return whether the Switch is off
70
85
  #
71
86
  # @return [Boolean]
72
- def off?; get_state == :off; end
87
+ def off?
88
+ get_state == :off
89
+ end
73
90
 
74
91
  # Return whether the Switch is on
75
92
  #
76
93
  # @return [Boolean]
77
- def on?; get_state == :on; end
94
+ def on?
95
+ get_state == :on
96
+ end
78
97
 
79
98
  # Monitors the state of the Switch via polling, and yields to the block
80
99
  # given with the updated state.
@@ -111,15 +130,19 @@ module Wemote
111
130
  async ? poller : poller.join
112
131
  end
113
132
 
114
- private
133
+ protected
115
134
 
116
135
  def get_state
136
+ self.get_binary_state() == '1' ? :on : :off
137
+ end
138
+
139
+ def get_binary_state
117
140
  response = begin
118
141
  client.post("http://#{@host}:#{@port}/upnp/control/basicevent1",Wemote::XML.get_binary_state,GET_HEADERS)
119
142
  rescue Exception
120
143
  client.post("http://#{@host}:#{@port}/upnp/control/basicevent1",Wemote::XML.get_binary_state,GET_HEADERS)
121
144
  end
122
- response.body.match(/<BinaryState>(\d)<\/BinaryState>/)[1] == '1' ? :on : :off
145
+ response.body.match(/<BinaryState>(\d)<\/BinaryState>/)[1]
123
146
  end
124
147
 
125
148
  def set_state(state)
@@ -135,22 +158,8 @@ module Wemote
135
158
  end
136
159
 
137
160
  def set_meta
138
- if @port
139
- response = client.get("http://#{@host}:#{@port}/setup.xml")
140
- @name = response.body.match(/<friendlyName>([^<]+)<\/friendlyName>/)[1]
141
- else
142
- for port in 49152..49156
143
- begin
144
- response = nil
145
- Timeout::timeout(1){ response = client.get("http://#{@host}:#{port}/setup.xml") }
146
- @name = response.body.match(/<friendlyName>([^<]+)<\/friendlyName>/)[1]
147
- @port = port
148
- break
149
- rescue Exception
150
- end
151
- end
152
- end
161
+ response = client.get("http://#{@host}:#{@port}/setup.xml")
162
+ @name = response.body.match(/<friendlyName>([^<]+)<\/friendlyName>/)[1]
153
163
  end
154
-
155
164
  end
156
165
  end
@@ -1,3 +1,3 @@
1
1
  module Wemote
2
- VERSION = "0.2.2"
2
+ VERSION = "0.2.3"
3
3
  end
@@ -4,7 +4,8 @@ module Wemote
4
4
  xml_path = File.join(File.dirname(__FILE__),'/../../xml')
5
5
  TEMPLATES = {
6
6
  get_binary_state: File.read(File.join(xml_path,'get_binary_state.xml')),
7
- set_binary_state: File.read(File.join(xml_path,'set_binary_state.xml'))
7
+ set_binary_state: File.read(File.join(xml_path,'set_binary_state.xml')),
8
+ get_insight_params: File.read(File.join(xml_path,'get_insight_params.xml'))
8
9
  }
9
10
 
10
11
  # @return [String] The required XML body for a Wemo binary state request
@@ -18,6 +19,11 @@ module Wemote
18
19
  TEMPLATES[:set_binary_state].gsub("{{1}}",state.to_s)
19
20
  end
20
21
 
22
+ def get_insight_params
23
+ TEMPLATES[:get_insight_params]
24
+ end
25
+
26
+
21
27
  end
22
28
  end
23
29
  end
@@ -18,4 +18,7 @@ Gem::Specification.new do |spec|
18
18
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
19
19
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
20
20
  spec.require_paths = ["lib"]
21
+
22
+ spec.add_dependency 'ssdp', '~> 1.1', '>= 1.1.6'
23
+
21
24
  end
@@ -1,6 +1,5 @@
1
1
  <?xml version="1.0" encoding="utf-8"?>
2
- <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"
3
- s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
2
+ <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
4
3
  <s:Body>
5
4
  <u:GetBinaryState xmlns:u="urn:Belkin:service:basicevent:1"/>
6
5
  </s:Body>
@@ -0,0 +1,6 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
3
+ <s:Body>
4
+ <u:GetInsightParams xmlns:u="urn:Belkin:service:insight:1"></u:GetInsightParams>
5
+ </s:Body>
6
+ </s:Envelope>
@@ -1,6 +1,5 @@
1
1
  <?xml version="1.0" encoding="utf-8"?>
2
- <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"
3
- s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
2
+ <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
4
3
  <s:Body>
5
4
  <u:SetBinaryState xmlns:u="urn:Belkin:service:basicevent:1">
6
5
  <BinaryState>{{1}}</BinaryState>
metadata CHANGED
@@ -1,15 +1,35 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: wemote
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.2.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kevin Gisi
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-08-08 00:00:00.000000000 Z
12
- dependencies: []
11
+ date: 2018-03-01 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: ssdp
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.1'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 1.1.6
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '1.1'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 1.1.6
13
33
  description: Wemote is a Ruby-agnostic gem for Wemo light switches
14
34
  email:
15
35
  - kevin@kevingisi.com
@@ -25,7 +45,9 @@ files:
25
45
  - Rakefile
26
46
  - lib/wemote.rb
27
47
  - lib/wemote/client.rb
48
+ - lib/wemote/collection/insight.rb
28
49
  - lib/wemote/collection/switch.rb
50
+ - lib/wemote/insight.rb
29
51
  - lib/wemote/switch.rb
30
52
  - lib/wemote/version.rb
31
53
  - lib/wemote/xml.rb
@@ -33,6 +55,7 @@ files:
33
55
  - spec/wemote/switch_spec.rb
34
56
  - wemote.gemspec
35
57
  - xml/get_binary_state.xml
58
+ - xml/get_insight_params.xml
36
59
  - xml/set_binary_state.xml
37
60
  homepage: https://github.com/gisikw/wemote
38
61
  licenses:
@@ -54,11 +77,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
54
77
  version: '0'
55
78
  requirements: []
56
79
  rubyforge_project:
57
- rubygems_version: 2.2.2
80
+ rubygems_version: 2.6.14
58
81
  signing_key:
59
82
  specification_version: 4
60
83
  summary: Wemote is a Ruby-agnostic gem for Wemo light switches
61
84
  test_files:
62
85
  - spec/spec_helper.rb
63
86
  - spec/wemote/switch_spec.rb
64
- has_rdoc: