ecobee 0.1.6 → 0.2.0

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: 50df9ac248431f92cafec6438d42aa0bb04d964f
4
- data.tar.gz: 1928432f79c576e9d6f88a04a00a5a8a8ca1d511
3
+ metadata.gz: f15c138cad29178c3935acfdffc88446ca994d35
4
+ data.tar.gz: 58581cf67d84e8e0e43b83b2375069aa70d41a9b
5
5
  SHA512:
6
- metadata.gz: dd700da725bca1f2b2cd79e371cbc14e9b8a85b2852c2433852d473fc561ec39b67a6dc90d454ef8235fc55a5fdb1945044535a14257a4ce5a6cdd627a2f13bb
7
- data.tar.gz: d06a3c81087115ef8d741c749bcc99ea52efd0cc668c2543f10c4b524bfec85ac65c4dfb715a62b327136e4c536f834133207e120aee6246f24ba4cefac05a63
6
+ metadata.gz: 6cb824a3793ecd6582479f00c94fad5d3819d4a7da373abdadbed6fdf7bb108a9072e7091780fb6f42842d60c648e827750a53e4a77c9455d3b59bc09faf325d
7
+ data.tar.gz: 5f8afab66b9bb155caf5b6f4691a72a8ada13765cfe64d3f83555bfcd910473d6f9d51115d87e81fbb8804593f90ed17d5f01c5ef0ecc04cd06c2d994358e9ed
@@ -19,6 +19,8 @@ Gem::Specification.new do |spec|
19
19
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
20
  spec.require_paths = ["lib"]
21
21
 
22
+ spec.required_ruby_version = '>= 2.0.0'
23
+
22
24
  spec.add_development_dependency "bundler", "~> 1.12"
23
25
  spec.add_development_dependency "rake", "~> 10.0"
24
26
  spec.add_development_dependency "rspec", "~> 3.0"
@@ -4,7 +4,9 @@
4
4
  # to change the mode. -- @robzr
5
5
 
6
6
  require 'pp'
7
- require 'ecobee'
7
+
8
+ #require 'ecobee'
9
+ require_relative '../lib/ecobee.rb'
8
10
 
9
11
  @hvac_modes = Ecobee::HVAC_MODES + ['quit']
10
12
 
@@ -14,7 +16,7 @@ class TestFunctions
14
16
  end
15
17
 
16
18
  def print_summary
17
- http_response = @client.get(
19
+ response = @client.get(
18
20
  'thermostat',
19
21
  {
20
22
  'selection' => {
@@ -25,7 +27,6 @@ class TestFunctions
25
27
  }
26
28
  }
27
29
  )
28
- response = JSON.parse(http_response.body)
29
30
 
30
31
  puts "Found %d thermostats." % response['thermostatList'].length
31
32
 
@@ -42,7 +43,7 @@ class TestFunctions
42
43
  end
43
44
 
44
45
  def update_mode(mode)
45
- http_response = @client.post(
46
+ @client.post(
46
47
  'thermostat',
47
48
  body: {
48
49
  'selection' => {
@@ -56,18 +57,16 @@ class TestFunctions
56
57
  }
57
58
  }
58
59
  )
59
- response = JSON.parse(http_response.body)
60
60
  end
61
61
  end
62
62
 
63
63
  token = Ecobee::Token.new(
64
64
  app_key: ENV['ECOBEE_APP_KEY'],
65
- app_name: 'set_mode',
66
- scope: :smartWrite,
67
- token_file: '~/.ecobee_token'
65
+ app_name: 'ecobee-gem'
68
66
  )
69
67
 
70
- puts token.pin_message if token.pin token.wait
68
+ puts token.pin_message if token.pin
69
+ token.wait
71
70
  test_functions = TestFunctions.new(
72
71
  Ecobee::Client.new(token: token)
73
72
  )
@@ -3,14 +3,11 @@
3
3
  # Refreshes token; displays details on saved token. -- @robzr
4
4
 
5
5
  require 'pp'
6
- require 'ecobee'
7
- require_relative '/Users/robzr/GitHub/ecobee/lib/ecobee/token.rb'
8
- require_relative '/Users/robzr/GitHub/ecobee/lib/ecobee/register.rb'
6
+ require_relative '../lib/ecobee.rb'
9
7
 
10
8
  token = Ecobee::Token.new(
11
- app_key: ENV['ECOBEE_API_KEY'],
12
- app_name: 'ecobee-gem',
13
- token_file: '~/.ecobee_token'
9
+ app_key: ENV['ECOBEE_APP_KEY'],
10
+ app_name: 'ecobee-gem'
14
11
  )
15
12
 
16
13
  puts token.pin_message if token.pin
@@ -18,6 +15,6 @@ token.wait
18
15
 
19
16
  puts "Access Token: #{token.access_token}"
20
17
  puts "Refresh Token: #{token.refresh_token}"
21
- puts "Expires At: #{token.expires_at}"
18
+ puts "Expires At: #{token.access_expires_at}"
22
19
  puts "Scope: #{token.scope}"
23
20
  puts "Type: #{token.type}"
@@ -2,31 +2,33 @@ require 'pp'
2
2
  require 'json'
3
3
  require 'net/http'
4
4
 
5
- require "ecobee/client"
6
- require "ecobee/register"
7
- require "ecobee/token"
8
- require "ecobee/version"
5
+ require 'ecobee/client'
6
+ require 'ecobee/register'
7
+ require 'ecobee/token'
8
+ require 'ecobee/version'
9
+ #require_relative 'ecobee/client'
10
+ #require_relative 'ecobee/register'
11
+ #require_relative 'ecobee/token'
12
+ #require_relative 'ecobee/version'
9
13
 
10
14
  module Ecobee
11
15
  API_HOST = 'api.ecobee.com'
12
16
  API_PORT = 443
13
17
  CONTENT_TYPE = ['application/json', { 'charset' => 'UTF-8' }]
14
-
18
+ DEFAULT_FILES = [
19
+ '~/Library/Mobile Documents/com~apple~CloudDocs/.ecobee_token',
20
+ '~/.ecobee_token'
21
+ ]
15
22
  HVAC_MODES = ['auto', 'auxHeatOnly', 'cool', 'heat', 'off']
16
-
17
- REFRESH_INTERVAL_PAD = 60
23
+ REFRESH_INTERVAL_PAD = 120
18
24
  REFRESH_TOKEN_CHECK = 10
19
-
20
- SCOPES = [:smartRead, :smartWrite]
21
-
25
+ SCOPES = [:smartWrite, :smartRead]
22
26
  URL_BASE= "https://#{API_HOST}:#{API_PORT}"
23
-
24
27
  URL_API = "#{URL_BASE}/1/"
25
28
  URL_GET_PIN = URL_BASE +
26
29
  '/authorize?response_type=ecobeePin&client_id=%s&scope=%s'
27
30
  URL_TOKEN = "#{URL_BASE}/token"
28
31
 
29
-
30
32
  def self.Model(model)
31
33
  { 'idtSmart' => 'ecobee Smart',
32
34
  'idtEms' => 'ecobee Smart EMS',
@@ -14,7 +14,10 @@ module Ecobee
14
14
  request = Net::HTTP::Get.new(URI(URI.escape(new_uri)))
15
15
  request['Content-Type'] = *CONTENT_TYPE
16
16
  request['Authorization'] = @token.authorization
17
- http.request(request)
17
+ http_response = http.request request
18
+ validate_status JSON.parse(http_response.body)
19
+ rescue JSON::ParserError => msg
20
+ raise ClientError.new("JSON::ParserError => #{msg}")
18
21
  end
19
22
 
20
23
  def post(arg, options: {}, body: nil)
@@ -24,7 +27,25 @@ module Ecobee
24
27
  request.body = JSON.generate(body) if body
25
28
  request['Content-Type'] = *CONTENT_TYPE
26
29
  request['Authorization'] = @token.authorization
27
- http.request(request)
30
+ http_response = http.request request
31
+ validate_status JSON.parse http_response.body
32
+ rescue JSON::ParserError => msg
33
+ raise ClientError.new("JSON::ParserError => #{msg}")
34
+ end
35
+
36
+ def validate_status(response)
37
+ if !response.key? 'status'
38
+ raise ClientError.new('Missing Status')
39
+ elsif !response['status'].key? 'code'
40
+ raise ClientError.new('Missing Status Code')
41
+ elsif response['status']['code'] != 0
42
+ raise ClientError.new(
43
+ "GET Error: #{response['status']['code']} " +
44
+ "Message: #{response['status']['message']}"
45
+ )
46
+ else
47
+ response
48
+ end
28
49
  end
29
50
 
30
51
  private
@@ -40,4 +61,6 @@ module Ecobee
40
61
 
41
62
  end
42
63
 
64
+ class ClientError < StandardError ; end
65
+
43
66
  end
@@ -44,6 +44,7 @@ module Ecobee
44
44
  rescue Exception => msg
45
45
  raise Ecobee::TokenError.new("Unknown Error: #{msg}")
46
46
  end
47
+
47
48
  end
48
49
 
49
50
  end
@@ -2,8 +2,8 @@ module Ecobee
2
2
  require 'date'
3
3
 
4
4
  class Token
5
- attr_reader :access_token,
6
- :expires_at,
5
+ attr_reader :access_expires_at,
6
+ :access_token,
7
7
  :pin,
8
8
  :pin_message,
9
9
  :refresh_token,
@@ -13,22 +13,28 @@ module Ecobee
13
13
  :type
14
14
 
15
15
  def initialize(
16
- app_key: nil,
16
+ access_expires_at: nil,
17
+ access_token: nil,
18
+ app_key: nil,
17
19
  app_name: nil,
18
20
  code: nil,
19
21
  refresh_token: nil,
20
22
  scope: SCOPES[0],
21
- token_file: nil
23
+ token_file: DEFAULT_FILES
22
24
  )
25
+ @access_expires_at = access_expires_at
26
+ @access_token = access_token
23
27
  @app_key = app_key
24
28
  @app_name = app_name
25
29
  @code = code
26
- @access_token, @code_expires_at, @expires_at, @pin, @type = nil
27
30
  @refresh_token = refresh_token
28
31
  @scope = scope
29
- @status = :authorization_pending
30
- @token_file = File.expand_path(token_file)
31
- parse_token_file unless @refresh_token
32
+ @token_file = expand_files token_file
33
+
34
+ @code_expires_at, @pin, @type = nil
35
+ parse_token_file
36
+ @status = @refresh_token ? :ready : :authorization_pending
37
+
32
38
  if @refresh_token
33
39
  refresh
34
40
  else
@@ -39,7 +45,7 @@ module Ecobee
39
45
  end
40
46
 
41
47
  def access_token
42
- refresh if Time.now + REFRESH_INTERVAL_PAD > @expires_at
48
+ refresh
43
49
  @access_token
44
50
  end
45
51
 
@@ -61,6 +67,7 @@ module Ecobee
61
67
  end
62
68
 
63
69
  def refresh
70
+ return if Time.now.to_i + REFRESH_INTERVAL_PAD < @access_expires_at
64
71
  response = Net::HTTP.post_form(
65
72
  URI(URL_TOKEN),
66
73
  'grant_type' => 'refresh_token',
@@ -69,14 +76,14 @@ module Ecobee
69
76
  )
70
77
  result = JSON.parse(response.body)
71
78
  if result.key? 'error'
72
- # pp result
79
+ pp result
73
80
  raise Ecobee::TokenError.new(
74
81
  "Result Error: (%s) %s" % [result['error'],
75
82
  result['error_description']]
76
83
  )
77
84
  else
78
85
  @access_token = result['access_token']
79
- @expires_at = Time.now + result['expires_in']
86
+ @access_expires_at = Time.now.to_i + result['expires_in']
80
87
  @refresh_token = result['refresh_token']
81
88
  @pin, @code, @code_expires_at = nil
82
89
  @scope = result['scope']
@@ -120,7 +127,7 @@ module Ecobee
120
127
  @status = :ready
121
128
  @access_token = result['access_token']
122
129
  @type = result['token_type']
123
- @expires_at = Time.now + result['expires_in']
130
+ @access_expires_at = Time.now.to_i + result['expires_in']
124
131
  @refresh_token = result['refresh_token']
125
132
  @scope = result['scope']
126
133
  @pin, @code, @code_expires_at = nil
@@ -134,6 +141,14 @@ module Ecobee
134
141
  raise Ecobee::TokenError.new("Unknown Error: #{msg}")
135
142
  end
136
143
 
144
+ def expand_files(token_file)
145
+ if token_file.is_a? Array
146
+ token_file.map { |tf| File.expand_path tf }
147
+ else
148
+ expand_files [token_file]
149
+ end
150
+ end
151
+
137
152
  def launch_monitor_thread
138
153
  Thread.new {
139
154
  loop do
@@ -145,34 +160,41 @@ module Ecobee
145
160
  end
146
161
 
147
162
  def parse_token_file
148
- #puts "Before Parse: app_key:#{@app_key} refresh_token:#{@refresh_token} pin:#{pin}"
149
- return unless (config = read_token_file).is_a? Hash
150
- section = (@app_name && config.key?(@app_name)) ? @app_name : @app_key
151
- if config.key?(section)
152
- @app_key ||= if config[section].key?('app_key')
153
- config[section]['app_key']
154
- else
155
- @app_name
156
- end
157
- if config[section].key?('refresh_token')
158
- @refresh_token ||= config[section]['refresh_token']
159
- elsif config[section].key?('pin')
160
- @pin ||= config[section]['pin']
161
- @code ||= config[section]['code']
162
- @code_expires_at ||= config[section]['code_expires_at'].to_i
163
- end
163
+ return unless (all_config = read_token_file).is_a? Hash
164
+ section = (@app_name && all_config.key?(@app_name)) ? @app_name : @app_key
165
+ return unless all_config.key?(section)
166
+ config = all_config[section]
167
+ @app_key ||= config.key?('app_key') ? config['app_key'] : @app_name
168
+ if config.key?('refresh_token')
169
+ @access_expires_at ||= config['access_expires_at'].to_i
170
+ @access_token ||= config['access_token']
171
+ @refresh_token ||= config['refresh_token']
172
+ @scope ||= config['scope']
173
+ @type ||= config['token_type']
174
+ elsif config.key?('pin')
175
+ @code ||= config['code']
176
+ @code_expires_at ||= config['code_expires_at'].to_i
177
+ @pin ||= config['pin']
164
178
  end
165
- #puts "After Parse: app_key:#{@app_key} refresh_token:#{@refresh_token} pin:#{pin}"
166
179
  end
167
180
 
168
- def read_token_file
181
+ def read_json_file(file)
169
182
  JSON.parse(
170
- File.open(@token_file, 'r').read(16 * 1024)
183
+ File.open(file, 'r').read(16 * 1024)
171
184
  )
185
+ rescue JSON::ParserError => msg
186
+ raise Ecobee::TokenError.new("Result parsing: #{msg}")
172
187
  rescue Errno::ENOENT
173
188
  {}
174
189
  end
175
190
 
191
+ def read_token_file
192
+ @token_file.each do |tf|
193
+ result = read_json_file(tf)
194
+ return result if result.length > 0
195
+ end
196
+ end
197
+
176
198
  def register
177
199
  result = Register.new(app_key: @app_key, scope: @scope)
178
200
  @pin = result.pin
@@ -184,7 +206,12 @@ module Ecobee
184
206
  end
185
207
 
186
208
  def write_token_file
187
- return unless @token_file
209
+ @token_file.each do |file|
210
+ return if write_json_file file
211
+ end
212
+ end
213
+
214
+ def write_json_file(file)
188
215
  if config = read_token_file
189
216
  config.delete(@app_name)
190
217
  config.delete(@app_key)
@@ -193,15 +220,22 @@ module Ecobee
193
220
  config[section] = {}
194
221
  config[section]['app_key'] = @app_key if @app_key && section != @app_key
195
222
  if @refresh_token
223
+ config[section]['access_token'] = @access_token
224
+ config[section]['access_expires_at'] = @access_expires_at
196
225
  config[section]['refresh_token'] = @refresh_token
226
+ config[section]['token_type'] = @type
227
+ config[section]['scope'] = @scope
197
228
  elsif @pin
198
229
  config[section]['pin'] = @pin
199
230
  config[section]['code'] = @code
200
231
  config[section]['code_expires_at'] = @code_expires_at
201
232
  end
202
- File.open(@token_file, 'w') do |tf|
233
+ File.open(file, 'w') do |tf|
203
234
  tf.puts JSON.pretty_generate(config)
204
235
  end
236
+ true
237
+ rescue Errno::ENOENT
238
+ nil
205
239
  end
206
240
 
207
241
  end
@@ -1,3 +1,3 @@
1
1
  module Ecobee
2
- VERSION = "0.1.6"
2
+ VERSION = "0.2.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ecobee
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.6
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rob Zwissler
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2016-08-06 00:00:00.000000000 Z
11
+ date: 2016-08-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -70,7 +70,6 @@ files:
70
70
  - bin/console
71
71
  - bin/setup
72
72
  - ecobee.gemspec
73
- - examples/bitbar_plugin.rb
74
73
  - examples/set_mode.rb
75
74
  - examples/test_token.rb
76
75
  - lib/ecobee.rb
@@ -90,7 +89,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
90
89
  requirements:
91
90
  - - ">="
92
91
  - !ruby/object:Gem::Version
93
- version: '0'
92
+ version: 2.0.0
94
93
  required_rubygems_version: !ruby/object:Gem::Requirement
95
94
  requirements:
96
95
  - - ">="
@@ -1,252 +0,0 @@
1
- #!/usr/bin/env ruby
2
- #
3
- # Allows for display and control of your Ecobee in the Mac OS X
4
- # menubar, using BitBar (http://getbitbar.com). -- @robzr
5
- #
6
- # <bitbar.title>EcobeeStat</bitbar.title>
7
- # <bitbar.version>v1.0</bitbar.version>
8
- # <bitbar.author>Rob Zwissler</bitbar.author>
9
- # <bitbar.author.github>robzr</bitbar.author.github>
10
- # <bitbar.desc>Ecobee Thermostat Control</bitbar.desc>
11
- # <bitbar.image>http://github.com/robzr/ecobee</bitbar.image>
12
- # <bitbar.dependencies>ruby</bitbar.dependencies>
13
- # <bitbar.abouturl>http://github.com/robzr/ecobee</bitbar.abouturl>
14
-
15
- require 'pp'
16
- require 'ecobee'
17
- #require_relative '/Users/robzr/GitHub/ecobee/lib/ecobee.rb'
18
- #require_relative '/Users/robzr/GitHub/ecobee/lib/ecobee/client.rb'
19
- #require_relative '/Users/robzr/GitHub/ecobee/lib/ecobee/token.rb'
20
- #require_relative '/Users/robzr/GitHub/ecobee/lib/ecobee/register.rb'
21
-
22
- API_KEY = 'u2Krw0OumeliB0OnwiaogySvgExhy2K4'
23
- HVAC_MODES = ['auto', 'auxHeatOnly', 'cool', 'heat', 'off', 'quit']
24
- DEG = '°'
25
-
26
- module Ecobee
27
- class ResponseError < StandardError ; end
28
-
29
- class BitBar
30
- def initialize(client)
31
- @client = client
32
- end
33
-
34
- def get_thermostat(args = {})
35
- index = args.delete(:index) || 0
36
- http_response = @client.get('thermostat',
37
- Ecobee::Selection(args))
38
- response = JSON.parse(http_response.body)
39
- get_thermostat_list_index(index: index,
40
- response: validate_status(response))
41
- rescue JSON::ParserError => msg
42
- raise ResponseError.new("JSON::ParserError => #{msg}")
43
- end
44
-
45
- def get_thermostat_list_index(index: 0, response: nil)
46
- if !response.key? 'thermostatList'
47
- raise ResponseError.new('Missing thermostatList')
48
- elsif index >= response['thermostatList'].length
49
- raise ResponseError.new(
50
- "Missing thermostatList Index #{index} (Max Found: " +
51
- "#{response['thermostatList'].length - 1})"
52
- )
53
- else
54
- response['thermostatList'][index]
55
- end
56
- end
57
-
58
- def validate_status(response)
59
- if !response.key? 'status'
60
- raise ResponseError.new('Missing Status')
61
- elsif !response['status'].key? 'code'
62
- raise ResponseError.new('Missing Status Code')
63
- elsif response['status']['code'] != 0
64
- raise ResponseError.new(
65
- "GET Error: #{response['status']['code']} " +
66
- "Message: #{response['status']['message']}"
67
- )
68
- else
69
- response
70
- end
71
- end
72
-
73
- # puts "Heat: #{info['runtime']['desiredHeat'] / 10}#{DEG} | color=red"
74
-
75
- def set_hold(cool_hold: nil, heat_hold: nil)
76
- functions = [{
77
- 'type' => 'setHold',
78
- 'params' => {
79
- 'holdType' => 'nextTransition',
80
- }
81
- }]
82
- functions[0]['params']['coolHoldTemp'] = cool_hold
83
- functions[0]['params']['heatHoldTemp'] = heat_hold
84
- http_response = @client.post(
85
- 'thermostat',
86
- body: {
87
- 'selection' => {
88
- 'selectionType' => 'registered',
89
- 'selectionMatch' => '',
90
- },
91
- 'functions' => functions
92
- }
93
- )
94
- response = JSON.parse(http_response.body)
95
- end
96
-
97
- def update_mode(mode)
98
- http_response = @client.post(
99
- 'thermostat',
100
- body: {
101
- 'selection' => {
102
- 'selectionType' => 'registered',
103
- 'selectionMatch' => '',
104
- },
105
- 'thermostat' => {
106
- 'settings' => {
107
- 'hvacMode' => mode
108
- }
109
- }
110
- }
111
- )
112
- response = JSON.parse(http_response.body)
113
- end
114
- end
115
- end
116
-
117
- def header(info)
118
- puts "#{info['runtime']['actualTemperature'] / 10.0}#{DEG}"
119
- puts '---'
120
- end
121
-
122
- def cool_menu(info)
123
- present_mode = info['settings']['hvacMode']
124
- return unless ['auto', 'cool'].include? present_mode
125
- puts "Cool: #{info['runtime']['desiredCool'] / 10}#{DEG} | color=blue"
126
- cool_low = info['settings']['coolRangeLow'] / 10
127
- cool_high = info['settings']['coolRangeHigh'] / 10
128
- (cool_low..cool_high).reverse_each do |temp|
129
- flag, color = ''
130
- flag = ' :arrow_left:' if temp == info['runtime']['actualTemperature'] / 10
131
- color = ' color=blue' if temp == info['runtime']['desiredCool'] / 10
132
- puts("--#{temp}#{DEG}#{flag}|#{color} bash=\"#{$0}\" " +
133
- "param1=\"set_cool=#{temp}\" refresh=true terminal=false")
134
- end
135
- end
136
-
137
- def heat_menu(info)
138
- present_mode = info['settings']['hvacMode']
139
- return unless ['auto', 'auxHeatOnly', 'heat'].include? present_mode
140
- puts "Heat: #{info['runtime']['desiredHeat'] / 10}#{DEG} | color=red"
141
- heat_low = info['settings']['heatRangeLow'] / 10
142
- heat_high = info['settings']['heatRangeHigh'] / 10
143
- (heat_low..heat_high).reverse_each do |temp|
144
- flag, color = ''
145
- flag = ' :arrow_left:' if temp == info['runtime']['actualTemperature'] / 10
146
- color = ' color=red' if temp == info['runtime']['desiredHeat'] / 10
147
- puts("--#{temp}#{DEG}#{flag}|#{color} bash=\"#{$0}\" " +
148
- "param1=\"set_heat=#{temp}\" refresh=true terminal=false")
149
- end
150
- end
151
-
152
- def mode_menu(info)
153
- puts "Mode: #{info['settings']['hvacMode']}"
154
- Ecobee::HVAC_MODES.reject { |mode| mode == info['settings']['hvacMode'] }
155
- .each do |mode|
156
- puts("--#{mode} | bash=\"#{$0}\" param1=\"set_mode=#{mode}\" " +
157
- "refresh=true terminal=false")
158
- end
159
- end
160
-
161
- def separator
162
- puts '---'
163
- end
164
-
165
- def stat_info(info)
166
- puts info['name']
167
- info['remoteSensors'].each do |sensor|
168
- temp = sensor['capability'].select do |cap|
169
- cap['type'] == 'temperature'
170
- end
171
- temp = temp[0]['value'].to_i / 10.0
172
- puts "--#{sensor['name']}: #{temp}#{DEG}"
173
- end
174
- puts "#{info['brand']} #{Ecobee::Model(info['modelNumber'])}"
175
- puts "Status: #{info['equipmentStatus']}"
176
- end
177
-
178
- def website
179
- puts 'Ecobee Web Portal|href="https://www.ecobee.com/consumerportal/index.html"'
180
- end
181
-
182
- token = Ecobee::Token.new(
183
- app_key: API_KEY, app_name: API_KEY,
184
- scope: :smartWrite,
185
- token_file: '~/.ecobee_token'
186
- )
187
- if token.pin
188
- puts "Ecobee | color=red"
189
- puts "---"
190
- puts "Registration Needed | color=red"
191
- puts "---"
192
- puts 'Login to Ecobee | href=\'https://www.ecobee.com/consumerportal/index.html\''
193
- puts 'Select \'My Apps\' from the drop-down menu'
194
- puts 'Press the \'Add Application\' button'
195
- puts "Enter authorization code: #{token.pin}"
196
- exit
197
- end
198
-
199
- ecobar = Ecobee::BitBar.new Ecobee::Client.new(token: token)
200
-
201
- case arg = ARGV.shift
202
- when /^dump/
203
- pp ecobar.get_thermostat(
204
- :includeRuntime => true,
205
- :includeExtendedRuntime => true,
206
- :includeElectricity => true,
207
- :includeSettings => true,
208
- :includeLocation => true,
209
- :includeProgram => true,
210
- :includeEvents => true,
211
- :includeDevice => true,
212
- :includeTechnician => true,
213
- :includeUtility => true,
214
- :includeAlerts => true,
215
- :includeWeather => true,
216
- :includeOemConfig => true,
217
- :includeEquipmentStatus => true,
218
- :includeNotificationSettings => true,
219
- :includeVersion => true,
220
- :includeSensors => true
221
- )
222
- when /^set_mode=/
223
- mode = arg.sub(/^.*=/, '')
224
- ecobar.update_mode mode
225
- when /^set_cool=/
226
- info = ecobar.get_thermostat(includeRuntime: true,
227
- includeSettings: true)
228
- cool_hold = arg.sub(/^.*=/, '').to_i * 10
229
- heat_hold = info['runtime']['desiredHeat']
230
-
231
- ecobar.set_hold(cool_hold: cool_hold, heat_hold: heat_hold)
232
- when /^set_heat=/
233
- info = ecobar.get_thermostat(includeRuntime: true,
234
- includeSettings: true)
235
- cool_hold = info['runtime']['desiredCool']
236
- heat_hold = arg.sub(/^.*=/, '').to_i * 10
237
-
238
- ecobar.set_hold(cool_hold: cool_hold, heat_hold: heat_hold)
239
- else
240
- info = ecobar.get_thermostat(includeRuntime: true,
241
- includeSettings: true,
242
- includeEquipmentStatus: true,
243
- includeSensors: true)
244
- header info
245
- cool_menu info
246
- heat_menu info
247
- separator
248
- stat_info info
249
- mode_menu info
250
- separator
251
- website
252
- end