smartermeter 0.2.1 → 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/CHANGELOG.md +5 -0
- data/Gemfile +1 -0
- data/LICENSE +7 -0
- data/README.md +17 -6
- data/Rakefile +82 -34
- data/icons/smartermeter-16x16.png +0 -0
- data/icons/smartermeter-32x32.png +0 -0
- data/icons/smartermeter.ico +0 -0
- data/icons/smartermeter.svg +1899 -0
- data/installer/launch4j.xml +27 -0
- data/{lib/smartermeter → installer}/main.rb +14 -0
- data/installer/nsis.nsi +102 -0
- data/lib/smartermeter/interfaces/swing.rb +406 -5
- data/lib/smartermeter/service.rb +3 -3
- data/lib/smartermeter.rb +1 -1
- data/smartermeter.gemspec +12 -6
- data/specs/fixtures/data.csv +1 -1
- data/specs/fixtures/expected_google_request.xml +70 -70
- data/specs/sample_spec.rb +8 -2
- metadata +23 -17
- data/build_configuration.rb +0 -89
@@ -0,0 +1,27 @@
|
|
1
|
+
<launch4jConfig>
|
2
|
+
<dontWrapJar>true</dontWrapJar>
|
3
|
+
<headerType>console</headerType>
|
4
|
+
<jar>jruby-complete.jar</jar>
|
5
|
+
<outfile>../pkg/base/smartermeter.exe</outfile>
|
6
|
+
<errTitle></errTitle>
|
7
|
+
<cmdLine>main.rb</cmdLine>
|
8
|
+
<chdir>.</chdir>
|
9
|
+
<priority>normal</priority>
|
10
|
+
<downloadUrl>http://java.com/download</downloadUrl>
|
11
|
+
<supportUrl></supportUrl>
|
12
|
+
<customProcName>true</customProcName>
|
13
|
+
<stayAlive>false</stayAlive>
|
14
|
+
<manifest></manifest>
|
15
|
+
<icon>../icons/smartermeter.ico</icon>
|
16
|
+
<var>GEM_HOME=gems</var>
|
17
|
+
<singleInstance>
|
18
|
+
<mutexName>smartermeter</mutexName>
|
19
|
+
<windowTitle>Smartermeter</windowTitle>
|
20
|
+
</singleInstance>
|
21
|
+
<jre>
|
22
|
+
<path></path>
|
23
|
+
<minVersion>1.6.0</minVersion>
|
24
|
+
<maxVersion></maxVersion>
|
25
|
+
<jdkPreference>preferJre</jdkPreference>
|
26
|
+
</jre>
|
27
|
+
</launch4jConfig>
|
@@ -1,11 +1,25 @@
|
|
1
1
|
# Used only to launch from a jar using rawr
|
2
2
|
|
3
|
+
require 'rubygems'
|
3
4
|
require 'jruby'
|
4
5
|
# This is needed for nokogiri to function properly under jruby
|
5
6
|
JRuby.objectspace=true
|
6
7
|
|
7
8
|
require 'smartermeter'
|
9
|
+
require 'smartermeter/daemon'
|
8
10
|
require 'smartermeter/interfaces/swing'
|
9
11
|
|
12
|
+
# Force character sets of all retrieved documents so that we don't have to have
|
13
|
+
# charsets.jar in the JRE
|
14
|
+
module WWW
|
15
|
+
class Mechanize
|
16
|
+
class Util
|
17
|
+
def self.detect_charset(src)
|
18
|
+
"ISO-8859-1"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
10
24
|
interface = SmarterMeter::Interfaces::Swing.new
|
11
25
|
SmarterMeter::Daemon.new(interface).start
|
data/installer/nsis.nsi
ADDED
@@ -0,0 +1,102 @@
|
|
1
|
+
;--------------------------------
|
2
|
+
;Include Modern UI
|
3
|
+
|
4
|
+
!include "MUI2.nsh"
|
5
|
+
|
6
|
+
;--------------------------------
|
7
|
+
;General
|
8
|
+
|
9
|
+
;Name and file
|
10
|
+
Name "Smartermeter (${VERSION})"
|
11
|
+
OutFile "../pkg/smartermeter-${VERSION}.exe"
|
12
|
+
|
13
|
+
;Default installation folder
|
14
|
+
InstallDir "$PROGRAMFILES\Smartermeter"
|
15
|
+
|
16
|
+
;Get installation folder from registry if available
|
17
|
+
InstallDirRegKey HKCU "Software\Smartermeter" ""
|
18
|
+
|
19
|
+
;Request application privileges for Windows Vista
|
20
|
+
RequestExecutionLevel user
|
21
|
+
|
22
|
+
;--------------------------------
|
23
|
+
;Interface Settings
|
24
|
+
|
25
|
+
!define MUI_ABORTWARNING
|
26
|
+
!define MUI_ICON "../icons/smartermeter.ico"
|
27
|
+
|
28
|
+
;--------------------------------
|
29
|
+
;Pages
|
30
|
+
|
31
|
+
!insertmacro MUI_PAGE_WELCOME
|
32
|
+
!insertmacro MUI_PAGE_LICENSE "..\LICENSE"
|
33
|
+
!insertmacro MUI_PAGE_COMPONENTS
|
34
|
+
!insertmacro MUI_PAGE_DIRECTORY
|
35
|
+
!insertmacro MUI_PAGE_INSTFILES
|
36
|
+
!insertmacro MUI_PAGE_FINISH
|
37
|
+
|
38
|
+
!insertmacro MUI_UNPAGE_WELCOME
|
39
|
+
!insertmacro MUI_UNPAGE_CONFIRM
|
40
|
+
!insertmacro MUI_UNPAGE_INSTFILES
|
41
|
+
!insertmacro MUI_UNPAGE_FINISH
|
42
|
+
|
43
|
+
;--------------------------------
|
44
|
+
;Languages
|
45
|
+
|
46
|
+
!insertmacro MUI_LANGUAGE "English"
|
47
|
+
|
48
|
+
;--------------------------------
|
49
|
+
;Installer Sections
|
50
|
+
|
51
|
+
Section "Smartermeter Base" SecBase
|
52
|
+
|
53
|
+
SetOutPath "$INSTDIR"
|
54
|
+
|
55
|
+
;ADD YOUR OWN FILES HERE...
|
56
|
+
File /r "../pkg/base/*"
|
57
|
+
|
58
|
+
CreateDirectory "$SMPROGRAMS\Smartermeter"
|
59
|
+
CreateShortCut "$SMPROGRAMS\Smartermeter\Smartermeter.lnk" "$INSTDIR\smartermeter.exe"
|
60
|
+
CreateShortCut "$SMPROGRAMS\Smartermeter\Uninstall.lnk" "$INSTDIR\uninstall.exe"
|
61
|
+
|
62
|
+
;Store installation folder
|
63
|
+
WriteRegStr HKCU "Software\Smartermeter" "" $INSTDIR
|
64
|
+
|
65
|
+
;Create uninstaller
|
66
|
+
WriteUninstaller "$INSTDIR\uninstall.exe"
|
67
|
+
SectionEnd
|
68
|
+
|
69
|
+
;--------------------------------
|
70
|
+
;Descriptions
|
71
|
+
|
72
|
+
;Language strings
|
73
|
+
LangString DESC_SecBase ${LANG_ENGLISH} "The smartermeter application."
|
74
|
+
|
75
|
+
;Assign language strings to sections
|
76
|
+
!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN
|
77
|
+
!insertmacro MUI_DESCRIPTION_TEXT ${SecBase} $(DESC_SecBase)
|
78
|
+
!insertmacro MUI_FUNCTION_DESCRIPTION_END
|
79
|
+
|
80
|
+
;--------------------------------
|
81
|
+
;Uninstaller Section
|
82
|
+
|
83
|
+
Section "Uninstall"
|
84
|
+
|
85
|
+
;ADD YOUR OWN FILES HERE...
|
86
|
+
|
87
|
+
Delete "$INSTDIR\*.rb"
|
88
|
+
Delete "$INSTDIR\*.jar"
|
89
|
+
Delete "$INSTDIR\*.exe"
|
90
|
+
RMDIR /r "$INSTDIR\gems"
|
91
|
+
RMDIR /r "$INSTDIR\icons"
|
92
|
+
RMDIR /r "$INSTDIR\smartermeter"
|
93
|
+
|
94
|
+
Delete "$SMPROGRAMS\Smartermeter\Smartermeter.lnk"
|
95
|
+
Delete "$SMPROGRAMS\Smartermeter\Uninstall.lnk"
|
96
|
+
RMDIR "$SMPROGRAMS\Smartermeter"
|
97
|
+
|
98
|
+
RMDir "$INSTDIR"
|
99
|
+
|
100
|
+
DeleteRegKey /ifempty HKCU "Software\Smartermeter"
|
101
|
+
|
102
|
+
SectionEnd
|
@@ -7,6 +7,8 @@ module SmarterMeter
|
|
7
7
|
class Swing
|
8
8
|
include_package "java.awt"
|
9
9
|
|
10
|
+
LogFile = File.expand_path("~/.smartermeter.log")
|
11
|
+
|
10
12
|
def initialize
|
11
13
|
# TODO: Implement a way to update the settings
|
12
14
|
#settings_item = MenuItem.new("Settings")
|
@@ -15,14 +17,29 @@ module SmarterMeter
|
|
15
17
|
# end
|
16
18
|
#}
|
17
19
|
|
20
|
+
update_item = MenuItem.new("Check for Updates")
|
21
|
+
update_item.add_action_listener do
|
22
|
+
desktop = Desktop.getDesktop();
|
23
|
+
uri = Java::JavaNet::URI.new("http://matt.colyer.name/projects/smartermeter/?v=#{SmarterMeter::VERSION}")
|
24
|
+
desktop.browse(uri)
|
25
|
+
end
|
26
|
+
|
27
|
+
log_item = MenuItem.new("View Log")
|
28
|
+
log_item.add_action_listener do
|
29
|
+
LogWindow.new {}
|
30
|
+
end
|
31
|
+
|
18
32
|
exit_item = MenuItem.new("Exit")
|
19
33
|
exit_item.add_action_listener {java.lang.System::exit(0)}
|
20
34
|
|
35
|
+
|
21
36
|
popup = PopupMenu.new
|
22
|
-
|
37
|
+
popup.add(update_item)
|
38
|
+
popup.add(log_item)
|
39
|
+
popup.add(MenuItem.new("-"))
|
23
40
|
popup.add(exit_item)
|
24
41
|
|
25
|
-
image = Toolkit::default_toolkit.get_image("
|
42
|
+
image = Toolkit::default_toolkit.get_image("icons/smartermeter-16x16.png")
|
26
43
|
tray_icon = TrayIcon.new(image, "Smartermeter", popup)
|
27
44
|
tray_icon.image_auto_size = true
|
28
45
|
|
@@ -33,7 +50,7 @@ module SmarterMeter
|
|
33
50
|
# Returns a logger like interface to log errors and warnings to.
|
34
51
|
def log
|
35
52
|
return @logger if @logger
|
36
|
-
@logger = Logger.new(
|
53
|
+
@logger = Logger.new(LogFile)
|
37
54
|
@logger.level = Logger::INFO
|
38
55
|
@logger
|
39
56
|
end
|
@@ -43,7 +60,7 @@ module SmarterMeter
|
|
43
60
|
#
|
44
61
|
# Returns nothing.
|
45
62
|
def setup
|
46
|
-
|
63
|
+
Wizard.new do |config|
|
47
64
|
yield config
|
48
65
|
end
|
49
66
|
end
|
@@ -53,6 +70,8 @@ module SmarterMeter
|
|
53
70
|
include_package "javax.swing"
|
54
71
|
|
55
72
|
def initialize(&block)
|
73
|
+
UIManager.set_look_and_feel(UIManager.get_system_look_and_feel_class_name)
|
74
|
+
|
56
75
|
layout = "
|
57
76
|
[ username_label | (150)username_field ]
|
58
77
|
[ password_label | (150)password_field ]
|
@@ -78,7 +97,389 @@ module SmarterMeter
|
|
78
97
|
end
|
79
98
|
|
80
99
|
@frame = @ui.build(:args => "Smartermeter Settings")
|
81
|
-
@frame.
|
100
|
+
@frame.set_location_relative_to(nil)
|
101
|
+
@frame.default_close_operation = JFrame::DISPOSE_ON_CLOSE
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
class LogWindow
|
106
|
+
include_package "javax.swing"
|
107
|
+
|
108
|
+
LogFile = File.expand_path("~/.smartermeter.log")
|
109
|
+
|
110
|
+
def initialize(&block)
|
111
|
+
UIManager.set_look_and_feel(UIManager.get_system_look_and_feel_class_name)
|
112
|
+
|
113
|
+
layout = "
|
114
|
+
[ log_label ]
|
115
|
+
[ (600,200)*log_area ]
|
116
|
+
[ >buttons ]
|
117
|
+
"
|
118
|
+
|
119
|
+
log = File.read(LogFile)
|
120
|
+
|
121
|
+
@ui = Profligacy::Swing::LEL.new(JFrame, layout) do |c,i|
|
122
|
+
c.log_label = JLabel.new "Log:"
|
123
|
+
|
124
|
+
textarea = JTextArea.new(log)
|
125
|
+
textarea.set_caret_position(textarea.get_text().length())
|
126
|
+
c.log_area = JScrollPane.new(textarea)
|
127
|
+
|
128
|
+
c.buttons = Profligacy::Swing::LEL.new(JPanel, "[clear|close]") do |cc,ii|
|
129
|
+
cc.clear = JButton.new "Clear"
|
130
|
+
ii.clear = { :action => proc do |t, e|
|
131
|
+
File.open(LogFile, "w") { |f| f.write("") }
|
132
|
+
textarea.text = ""
|
133
|
+
end
|
134
|
+
}
|
135
|
+
cc.close = JButton.new "Close"
|
136
|
+
ii.close = { :action => proc do |t, e|
|
137
|
+
@frame.dispose
|
138
|
+
yield
|
139
|
+
end
|
140
|
+
}
|
141
|
+
end.build :auto_create_container_gaps => false
|
142
|
+
end
|
143
|
+
|
144
|
+
@frame = @ui.build(:args => "Smartermeter Log")
|
145
|
+
@frame.set_location_relative_to(nil)
|
146
|
+
@frame.default_close_operation = JFrame::DISPOSE_ON_CLOSE
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
class Wizard
|
151
|
+
include_package "javax.swing"
|
152
|
+
include_package "java.awt"
|
153
|
+
|
154
|
+
def initialize
|
155
|
+
UIManager.set_look_and_feel(UIManager.get_system_look_and_feel_class_name)
|
156
|
+
|
157
|
+
layout = "
|
158
|
+
[ panel ]
|
159
|
+
[ rule ]
|
160
|
+
[ >buttons ]
|
161
|
+
"
|
162
|
+
|
163
|
+
@page_index = 0
|
164
|
+
|
165
|
+
@wizard = Profligacy::Swing::LEL.new(JFrame, layout) do |c,i|
|
166
|
+
c.rule = JSeparator.new
|
167
|
+
|
168
|
+
@buttons = Profligacy::Swing::LEL.new(JPanel, "[back|next|>gap|cancel]") do |cc,ii|
|
169
|
+
cc.back = JButton.new "Back"
|
170
|
+
cc.back.minimum_size = Dimension.new(50,14)
|
171
|
+
cc.back.visible = false
|
172
|
+
ii.back = { :action => method(:show_previous_page) }
|
173
|
+
|
174
|
+
cc.next = JButton.new "Next"
|
175
|
+
cc.next.minimum_size = Dimension.new(50,14)
|
176
|
+
cc.next.enabled = false
|
177
|
+
ii.next = { :action => method(:show_next_page) }
|
178
|
+
|
179
|
+
cc.gap = Box.create_horizontal_strut(10)
|
180
|
+
|
181
|
+
cc.cancel = JButton.new "Cancel"
|
182
|
+
cc.cancel.minimum_size = Dimension.new(50,14)
|
183
|
+
ii.cancel = { :action => proc do |t, e|
|
184
|
+
if cc.cancel.text == "Complete"
|
185
|
+
config = {
|
186
|
+
:username => @pages[0].username,
|
187
|
+
:password => @pages[0].password,
|
188
|
+
:transport => :google_powermeter,
|
189
|
+
:google_powermeter => {
|
190
|
+
:token => @pages[1].token,
|
191
|
+
:variable => @pages[1].variable,
|
192
|
+
:auth => @pages[1].auth
|
193
|
+
}
|
194
|
+
}
|
195
|
+
else
|
196
|
+
config = {}
|
197
|
+
end
|
198
|
+
|
199
|
+
@frame.dispose
|
200
|
+
yield config
|
201
|
+
end
|
202
|
+
}
|
203
|
+
end
|
204
|
+
c.buttons = @buttons.build
|
205
|
+
|
206
|
+
@panel = JPanel.new(CardLayout.new)
|
207
|
+
@pages = [PGEPage, GooglePowerMeterPage, CompletePage].map do |klass|
|
208
|
+
page = klass.new(@buttons)
|
209
|
+
@panel.add(page.build, klass.to_s)
|
210
|
+
page
|
211
|
+
end
|
212
|
+
c.panel = @panel
|
213
|
+
end
|
214
|
+
|
215
|
+
@frame = @wizard.build(:args => "SmarterMeter Setup", :auto_create_container_gaps => false) do |frame|
|
216
|
+
frame.default_close_operation = JFrame::DISPOSE_ON_CLOSE
|
217
|
+
frame.set_size(560, 400)
|
218
|
+
frame.set_location_relative_to(nil) # Centers on screen
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
# Public: Presents the next page of the wizard.
|
223
|
+
#
|
224
|
+
# type - The symbol representing the name of the event called
|
225
|
+
# event - The Java::Awt::Event that was triggered.
|
226
|
+
#
|
227
|
+
# Returns nothing.
|
228
|
+
def show_next_page(type, event)
|
229
|
+
@page_index += 1
|
230
|
+
configure_buttons
|
231
|
+
|
232
|
+
@panel.get_layout.next(@panel)
|
233
|
+
end
|
234
|
+
|
235
|
+
# Public: Presents the previous page of the wizard.
|
236
|
+
#
|
237
|
+
# type - The symbol representing the name of the event called
|
238
|
+
# event - The Java::Awt::Event that was triggered.
|
239
|
+
#
|
240
|
+
# Returns nothing.
|
241
|
+
def show_previous_page(type, event)
|
242
|
+
@page_index -= 1
|
243
|
+
configure_buttons
|
244
|
+
|
245
|
+
@panel.get_layout.previous(@panel)
|
246
|
+
end
|
247
|
+
|
248
|
+
protected
|
249
|
+
|
250
|
+
def configure_buttons
|
251
|
+
@pages[@page_index].validate
|
252
|
+
|
253
|
+
if @page_index > 0
|
254
|
+
@buttons.back.visible = true
|
255
|
+
else
|
256
|
+
@buttons.back.visible = false
|
257
|
+
end
|
258
|
+
|
259
|
+
if @page_index == @pages.size - 1
|
260
|
+
@buttons.next.visible = false
|
261
|
+
@buttons.cancel.text = "Complete"
|
262
|
+
else
|
263
|
+
@buttons.next.visible = true
|
264
|
+
@buttons.cancel.text = "Cancel"
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
module WizardPage
|
269
|
+
include_package "javax.swing"
|
270
|
+
include_package "java.awt"
|
271
|
+
|
272
|
+
# Protected: Creates a panel that includes the header at the top, in
|
273
|
+
# a standard wizard visual format.
|
274
|
+
#
|
275
|
+
# It expects a block, which yields a Profligacy::Swing::LEL object
|
276
|
+
# to attach components and events to.
|
277
|
+
#
|
278
|
+
# header("Title", "Message") do |c|
|
279
|
+
# c.controls = JButton.new("Hello World!")
|
280
|
+
# end
|
281
|
+
#
|
282
|
+
# title - The text to show in the header as the title.
|
283
|
+
# message - The text to show under the title in the header.
|
284
|
+
# controls - True adds a controls area to the page, false ignores it.
|
285
|
+
# Defaults to true.
|
286
|
+
#
|
287
|
+
# Returns nothing.
|
288
|
+
def header(title, message, controls=true)
|
289
|
+
layout = "
|
290
|
+
[ (560,100)*header ]
|
291
|
+
"
|
292
|
+
layout += "[ controls ]" if controls
|
293
|
+
|
294
|
+
@panel = Profligacy::Swing::LEL.new(JPanel, layout) do |c,i|
|
295
|
+
header_layout = "
|
296
|
+
[ <title ]
|
297
|
+
[ <message ]
|
298
|
+
"
|
299
|
+
@header = Profligacy::Swing::LEL.new(JPanel, header_layout) do |cc,ii|
|
300
|
+
cc.title = JLabel.new title
|
301
|
+
cc.message = JEditorPane.new "text/html", message
|
302
|
+
cc.message.background = Color::WHITE
|
303
|
+
cc.message.editable = false
|
304
|
+
cc.message.border = BorderFactory.createEmptyBorder(0, 30, 0, 0)
|
305
|
+
ii.message = { :hyperlink => proc do |t, e|
|
306
|
+
if e.event_type.to_s == "ACTIVATED"
|
307
|
+
desktop = Desktop.getDesktop()
|
308
|
+
uri = Java::JavaNet::URI.new(e.url.to_s)
|
309
|
+
desktop.browse(uri)
|
310
|
+
end
|
311
|
+
end
|
312
|
+
}
|
313
|
+
end
|
314
|
+
|
315
|
+
c.header = @header.build
|
316
|
+
c.header.background = Color::WHITE
|
317
|
+
|
318
|
+
yield c if block_given?
|
319
|
+
end
|
320
|
+
end
|
321
|
+
|
322
|
+
def build
|
323
|
+
@panel.build(:auto_create_container_gaps => false)
|
324
|
+
end
|
325
|
+
end
|
326
|
+
|
327
|
+
# Contains the controls and messaging for the PGE page of the wizard.
|
328
|
+
class PGEPage
|
329
|
+
include_package "javax.swing"
|
330
|
+
include_package "java.awt"
|
331
|
+
include WizardPage
|
332
|
+
|
333
|
+
def initialize(buttons)
|
334
|
+
@global_buttons = buttons
|
335
|
+
|
336
|
+
title = "<html><b>Connect to PG&E</b></html>"
|
337
|
+
message = "Enter your PG&E username and password. If you don't have one,"
|
338
|
+
message += "create one first and then enter it below."
|
339
|
+
|
340
|
+
header(title, message) do |c|
|
341
|
+
layout = "
|
342
|
+
[ username_label | <username_field ]
|
343
|
+
[ password_label | <password_field ]
|
344
|
+
[ _ | create ]
|
345
|
+
"
|
346
|
+
|
347
|
+
@controls = Profligacy::Swing::LEL.new(JPanel, layout) do |cc,ii|
|
348
|
+
cc.username_label = JLabel.new "PG&E Username:"
|
349
|
+
cc.username_field = JTextField.new
|
350
|
+
cc.username_field.maximum_size = Dimension.new(160,14)
|
351
|
+
ii.username_field = { :key => method(:validate) }
|
352
|
+
|
353
|
+
cc.password_label = JLabel.new "PG&E Password:"
|
354
|
+
cc.password_field = JPasswordField.new
|
355
|
+
cc.password_field.maximum_size = Dimension.new(160,14)
|
356
|
+
ii.password_field = { :key => method(:validate) }
|
357
|
+
|
358
|
+
cc.create = JButton.new "Create a PG&E Account"
|
359
|
+
ii.create = { :action => method(:open_pge_sign_up_flow) }
|
360
|
+
end
|
361
|
+
c.controls = @controls.build
|
362
|
+
end
|
363
|
+
end
|
364
|
+
|
365
|
+
# Public: Get the currently set username
|
366
|
+
def username
|
367
|
+
@controls.username_field.text
|
368
|
+
end
|
369
|
+
|
370
|
+
# Public: Get the currently set username
|
371
|
+
def password
|
372
|
+
@controls.password_field.text
|
373
|
+
end
|
374
|
+
|
375
|
+
# Determines whether a user has entered both a username and
|
376
|
+
# password. If they have then the next button is enabled.
|
377
|
+
#
|
378
|
+
# Returns nothing.
|
379
|
+
def validate(*ignored_args)
|
380
|
+
valid = @controls.password_field.text.size > 0 and @controls.username_field.text.size > 0
|
381
|
+
@global_buttons.next.enabled = valid
|
382
|
+
end
|
383
|
+
|
384
|
+
# Opens the PG&E sign up flow for a user to create an account online
|
385
|
+
# if they haven't already.
|
386
|
+
#
|
387
|
+
# type - The symbol representing the name of the event called
|
388
|
+
# event - The Java::Awt::Event that was triggered.
|
389
|
+
#
|
390
|
+
# Returns nothing.
|
391
|
+
def open_pge_sign_up_flow(type, event)
|
392
|
+
desktop = Desktop.getDesktop()
|
393
|
+
uri = Java::JavaNet::URI.new("https://www.pge.com/eum/registration?TARGET=https://www.pge.com/csol")
|
394
|
+
desktop.browse(uri)
|
395
|
+
end
|
396
|
+
end
|
397
|
+
|
398
|
+
class GooglePowerMeterPage
|
399
|
+
include_package "javax.swing"
|
400
|
+
include_package "java.awt"
|
401
|
+
include WizardPage
|
402
|
+
|
403
|
+
def initialize(buttons)
|
404
|
+
@buttons = buttons
|
405
|
+
|
406
|
+
title = "<html><b>Connect to Google PowerMeter</b></html>"
|
407
|
+
message = "In order to view your power data on Google PowerMeter you'll need to create an account."
|
408
|
+
|
409
|
+
header(title, message) do |c|
|
410
|
+
layout = "
|
411
|
+
[ create ]
|
412
|
+
[ auth_label ]
|
413
|
+
[ auth_field ]
|
414
|
+
"
|
415
|
+
@controls = Profligacy::Swing::LEL.new(JPanel, layout) do |cc,ii|
|
416
|
+
cc.create = JButton.new "Create a PowerMeter Account"
|
417
|
+
ii.create = { :action => method(:open_google_powermeter_registration) }
|
418
|
+
cc.auth_label = JLabel.new "Then, copy your Authorization Information below:"
|
419
|
+
cc.auth_field = JTextArea.new
|
420
|
+
cc.auth_field.line_wrap = true
|
421
|
+
cc.auth_field.minimum_size = Dimension.new(400, 80)
|
422
|
+
cc.auth_field.maximum_size = Dimension.new(400, 80)
|
423
|
+
ii.auth_field = { :key => method(:validate) }
|
424
|
+
end
|
425
|
+
c.controls = @controls.build
|
426
|
+
end
|
427
|
+
end
|
428
|
+
|
429
|
+
def token
|
430
|
+
CGI.parse(@controls.auth_field.text.strip)["token"][0]
|
431
|
+
end
|
432
|
+
|
433
|
+
def variable
|
434
|
+
CGI.parse(@controls.auth_field.text.strip)["path"][0]+".d1"
|
435
|
+
end
|
436
|
+
|
437
|
+
def auth
|
438
|
+
@controls.auth_field.text.strip
|
439
|
+
end
|
440
|
+
|
441
|
+
# Opens the Google Powermeter registration flow so that users can upload
|
442
|
+
# their data.
|
443
|
+
#
|
444
|
+
# Returns nothing.
|
445
|
+
def open_google_powermeter_registration(*ignored_args)
|
446
|
+
desktop = Desktop.getDesktop()
|
447
|
+
uri = Java::JavaNet::URI.new("https://www.google.com/powermeter/device/activate?mfg=SmarterMeter&model=SmarterMeter&did=PGE&dvars=1")
|
448
|
+
desktop.browse(uri)
|
449
|
+
end
|
450
|
+
|
451
|
+
# Determines whether a user has entered authorization information from
|
452
|
+
# Google.
|
453
|
+
#
|
454
|
+
# Returns nothing.
|
455
|
+
def validate(*ignored_args)
|
456
|
+
@buttons.next.enabled = @controls.auth_field.text.size > 0
|
457
|
+
end
|
458
|
+
end
|
459
|
+
|
460
|
+
class CompletePage
|
461
|
+
include_package "javax.swing"
|
462
|
+
include_package "java.awt"
|
463
|
+
include WizardPage
|
464
|
+
|
465
|
+
def initialize(buttons)
|
466
|
+
@buttons = buttons
|
467
|
+
|
468
|
+
title = "<html><b>SmarterMeter Setup Complete</b></html>"
|
469
|
+
message = "SmarterMeter will now run in your taskbar and periodically check for new power data "
|
470
|
+
message += "and relay it to Google PowerMeter.<br><br>"
|
471
|
+
message += "If you encounter an issue or would like to help improve SmarterMeter visit <a href='http://github.com/mcolyer/smartermeter/'>http://github.com/mcolyer/smatermeter</a>"
|
472
|
+
message += "<br><br>Enjoy!"
|
473
|
+
|
474
|
+
header(title, message, false)
|
475
|
+
end
|
476
|
+
|
477
|
+
# Enable the next button
|
478
|
+
#
|
479
|
+
# Returns nothing.
|
480
|
+
def validate(*ignored_args)
|
481
|
+
@buttons.next.enabled = true
|
482
|
+
end
|
82
483
|
end
|
83
484
|
end
|
84
485
|
end
|
data/lib/smartermeter/service.rb
CHANGED
@@ -11,7 +11,7 @@ module SmarterMeter
|
|
11
11
|
attr_reader :last_exception
|
12
12
|
|
13
13
|
def initialize
|
14
|
-
@agent =
|
14
|
+
@agent = Mechanize.new { |agent|
|
15
15
|
agent.user_agent_alias = 'Mac Safari'
|
16
16
|
}
|
17
17
|
end
|
@@ -68,7 +68,7 @@ module SmarterMeter
|
|
68
68
|
# parameters first before we can get the exportable data. This really shouldn't
|
69
69
|
# be necessary.
|
70
70
|
begin
|
71
|
-
hourly_data = @data_page.form_with(:action => "
|
71
|
+
hourly_data = @data_page.form_with(:action => "LoadAnalysis.aspx") do |form|
|
72
72
|
form['__EVENTTARGET'] = "objChartSelect$butSubmit"
|
73
73
|
form['objTimePeriods$objExport$hidChart'] = "Hourly Usage"
|
74
74
|
form['objTimePeriods$objExport$hidChartID'] = 8
|
@@ -82,7 +82,7 @@ module SmarterMeter
|
|
82
82
|
end.submit
|
83
83
|
|
84
84
|
# Now the beautiful data...
|
85
|
-
hourly_csv = hourly_data.form_with(:action => "
|
85
|
+
hourly_csv = hourly_data.form_with(:action => "LoadAnalysis.aspx") do |form|
|
86
86
|
form['__EVENTTARGET'] = "objTimePeriods$objExport$butExport"
|
87
87
|
end.submit
|
88
88
|
|
data/lib/smartermeter.rb
CHANGED
data/smartermeter.gemspec
CHANGED
@@ -13,8 +13,8 @@ Gem::Specification.new do |s|
|
|
13
13
|
## If your rubyforge_project name is different, then edit it and comment out
|
14
14
|
## the sub! line in the Rakefile
|
15
15
|
s.name = 'smartermeter'
|
16
|
-
s.version = '0.
|
17
|
-
s.date = '2011-
|
16
|
+
s.version = '0.3.0'
|
17
|
+
s.date = '2011-03-14'
|
18
18
|
s.rubyforge_project = 'smartermeter'
|
19
19
|
|
20
20
|
## Make sure your summary is short. The description may be as long
|
@@ -48,13 +48,13 @@ Gem::Specification.new do |s|
|
|
48
48
|
|
49
49
|
## List your runtime dependencies here. Runtime dependencies are those
|
50
50
|
## that are needed for an end user to actually USE your code.
|
51
|
-
s.add_dependency('mechanize', ["= 0.
|
51
|
+
s.add_dependency('mechanize', ["= 1.0.0"])
|
52
52
|
s.add_dependency('crypt', ["= 1.1.4"])
|
53
53
|
|
54
54
|
## List your development dependencies here. Development dependencies are
|
55
55
|
## those that are only needed during development
|
56
|
-
s.add_development_dependency('rawr', ["~> 1.4.5"])
|
57
56
|
s.add_development_dependency('rspec', ["~> 2.4.0"])
|
57
|
+
s.add_development_dependency('minitar', ["~> 0.5.2"])
|
58
58
|
|
59
59
|
## Leave this section as-is. It will be automatically generated from the
|
60
60
|
## contents of your Git repository via the gemspec task. DO NOT REMOVE
|
@@ -63,15 +63,21 @@ Gem::Specification.new do |s|
|
|
63
63
|
s.files = %w[
|
64
64
|
CHANGELOG.md
|
65
65
|
Gemfile
|
66
|
+
LICENSE
|
66
67
|
README.md
|
67
68
|
Rakefile
|
68
69
|
bin/smartermeter
|
69
|
-
|
70
|
+
icons/smartermeter-16x16.png
|
71
|
+
icons/smartermeter-32x32.png
|
72
|
+
icons/smartermeter.ico
|
73
|
+
icons/smartermeter.svg
|
74
|
+
installer/launch4j.xml
|
75
|
+
installer/main.rb
|
76
|
+
installer/nsis.nsi
|
70
77
|
lib/smartermeter.rb
|
71
78
|
lib/smartermeter/daemon.rb
|
72
79
|
lib/smartermeter/interfaces/cli.rb
|
73
80
|
lib/smartermeter/interfaces/swing.rb
|
74
|
-
lib/smartermeter/main.rb
|
75
81
|
lib/smartermeter/sample.rb
|
76
82
|
lib/smartermeter/service.rb
|
77
83
|
lib/smartermeter/transports/cacert.pem
|