smartermeter 0.3.1 → 0.3.2
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 +6 -0
- data/Gemfile +3 -2
- data/README.md +21 -1
- data/Rakefile +9 -1
- data/lib/smartermeter/daemon.rb +6 -3
- data/lib/smartermeter/interfaces/swing.rb +2 -0
- data/lib/smartermeter/sample.rb +16 -43
- data/lib/smartermeter/samples.rb +65 -0
- data/lib/smartermeter/service.rb +22 -1
- data/lib/smartermeter/services/brighterplanet.rb +59 -0
- data/lib/smartermeter/{transports → services}/cacert.pem +0 -0
- data/lib/smartermeter/{transports → services}/google_powermeter.erb +0 -0
- data/lib/smartermeter/{transports → services}/google_powermeter.rb +1 -1
- data/lib/smartermeter.rb +4 -2
- data/smartermeter.gemspec +23 -14
- data/{specs → spec}/fixtures/data.csv +0 -0
- data/{specs → spec}/fixtures/expected_google_request.xml +0 -0
- data/spec/fixtures/vcr_cassettes/brighterplanet.yml +106 -0
- data/spec/sample_spec.rb +8 -0
- data/spec/samples_spec.rb +39 -0
- data/{specs → spec}/service_spec.rb +0 -1
- data/spec/services/brighterplanet_spec.rb +26 -0
- data/{specs/transports → spec/services}/google_powermeter_spec.rb +4 -4
- data/{specs → spec}/spec_helper.rb +6 -0
- metadata +75 -44
- data/specs/sample_spec.rb +0 -24
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,11 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## 0.3.2 (March 29, 2011)
|
4
|
+
* Added support for Brighter Planet's Electricity API.
|
5
|
+
* Fixed encryption of passwords that had lengths other than multiples of
|
6
|
+
8.
|
7
|
+
* Added more extensive documentation of the library.
|
8
|
+
|
3
9
|
## 0.3.1 (March 15th, 2011)
|
4
10
|
* Changed name from "Smartermeter" to "SmarterMeter"
|
5
11
|
* Updated the .detect\_charset monkeypatch for the newer mechanize
|
data/Gemfile
CHANGED
@@ -2,5 +2,6 @@ source :rubygems
|
|
2
2
|
gemspec
|
3
3
|
|
4
4
|
# Used only in the Java client, which isn't distributed as a gem
|
5
|
-
gem "
|
6
|
-
gem "jruby
|
5
|
+
gem "nokogiri", ">= 1.4.4", :platforms => :jruby
|
6
|
+
gem "profligacy", :platforms => :jruby
|
7
|
+
gem "jruby-openssl", :platforms => :jruby
|
data/README.md
CHANGED
@@ -15,6 +15,25 @@ Getting Started
|
|
15
15
|
gem install smartermeter
|
16
16
|
smartermeter
|
17
17
|
|
18
|
+
Manipulating the data
|
19
|
+
---------------------
|
20
|
+
|
21
|
+
After you've successfully downloaded one set of data, you should be able
|
22
|
+
to manipulate it using ruby like so:
|
23
|
+
|
24
|
+
require 'rubygems'
|
25
|
+
require 'smartermeter'
|
26
|
+
|
27
|
+
config = YAML.load_file(File.expand_path("~/.smartermeter"))
|
28
|
+
csv_file = Dir.glob(File.join(config[:data_dir], "*.csv")).last
|
29
|
+
|
30
|
+
samples = SmarterMeter::Samples.parse_csv(csv_file)
|
31
|
+
kwh_used = samples.total_kwh
|
32
|
+
api = SmarterMeter::Services::BrighterPlanet.new
|
33
|
+
puts api.calculate_kg_carbon(kwh_used)
|
34
|
+
|
35
|
+
For futher information see the [API docs][rdoc]
|
36
|
+
|
18
37
|
Google PowerMeter
|
19
38
|
-----------------
|
20
39
|
|
@@ -44,7 +63,7 @@ In order to build the self contained binaries, you'll need Java 1.6 and
|
|
44
63
|
apt-get install nsis sun-java6-jre
|
45
64
|
git clone git://github.com/mcolyer/smartermeter.git
|
46
65
|
cd smartermeter
|
47
|
-
bundle install --path vendor/gems
|
66
|
+
bundle install --path vendor/gems
|
48
67
|
rake package
|
49
68
|
|
50
69
|
The installer will be generated in pkg/
|
@@ -76,3 +95,4 @@ part of their [Fellowship Program][3]
|
|
76
95
|
[1]: http://nsis.sourceforge.net/
|
77
96
|
[2]: http://brighterplanet.com/
|
78
97
|
[3]: http://brighterplanet.github.com/fellowship.html
|
98
|
+
[rdoc]: http://rdoc.info/github/mcolyer/smartermeter/master/frames
|
data/Rakefile
CHANGED
@@ -48,7 +48,7 @@ task :default => :test
|
|
48
48
|
require 'rake/testtask'
|
49
49
|
Rake::TestTask.new(:test) do |test|
|
50
50
|
test.libs << 'lib' << 'test'
|
51
|
-
test.pattern = '
|
51
|
+
test.pattern = 'spec/**/*_spec.rb'
|
52
52
|
test.verbose = true
|
53
53
|
end
|
54
54
|
|
@@ -122,6 +122,10 @@ task :package_gems do
|
|
122
122
|
specifications.reject! { |s| s.include? "rspec" }
|
123
123
|
specifications.reject! { |s| s.include? "minitar" }
|
124
124
|
specifications.reject! { |s| s.include? "ruby-debug" }
|
125
|
+
specifications.reject! { |s| s.include? "addressable" }
|
126
|
+
specifications.reject! { |s| s.include? "diff-lcs" }
|
127
|
+
specifications.reject! { |s| s.include? "vcr" }
|
128
|
+
specifications.reject! { |s| s.include? "webmock" }
|
125
129
|
dest_dir = File.join(File.dirname(__FILE__), "pkg", "base", "gems", "specifications")
|
126
130
|
FileUtils.rm_rf(dest_dir)
|
127
131
|
FileUtils.mkdir_p(dest_dir)
|
@@ -131,6 +135,10 @@ task :package_gems do
|
|
131
135
|
gems.reject! { |s| s.include? "rspec" }
|
132
136
|
gems.reject! { |s| s.include? "minitar" }
|
133
137
|
gems.reject! { |s| s.include? "ruby-debug" }
|
138
|
+
gems.reject! { |s| s.include? "addressable" }
|
139
|
+
gems.reject! { |s| s.include? "diff-lcs" }
|
140
|
+
gems.reject! { |s| s.include? "vcr" }
|
141
|
+
gems.reject! { |s| s.include? "webmock" }
|
134
142
|
dest_dir = File.join(File.dirname(__FILE__), "pkg", "base", "gems", "gems")
|
135
143
|
FileUtils.rm_rf(dest_dir)
|
136
144
|
FileUtils.mkdir_p(dest_dir)
|
data/lib/smartermeter/daemon.rb
CHANGED
@@ -4,6 +4,7 @@ require 'yaml'
|
|
4
4
|
require 'date'
|
5
5
|
|
6
6
|
module SmarterMeter
|
7
|
+
# @private
|
7
8
|
class Daemon
|
8
9
|
|
9
10
|
def initialize(interface)
|
@@ -63,6 +64,8 @@ module SmarterMeter
|
|
63
64
|
|
64
65
|
# Takes the unencrypted password and encrypts it.
|
65
66
|
def password=(unencrypted)
|
67
|
+
padding_length = 8 - (unencrypted.bytesize % 8)
|
68
|
+
unencrypted = unencrypted + ("\0" * padding_length)
|
66
69
|
@config[:password] = cipher.encrypt_block(unencrypted)
|
67
70
|
end
|
68
71
|
|
@@ -70,7 +73,7 @@ module SmarterMeter
|
|
70
73
|
def password
|
71
74
|
password = @config.fetch(:password, nil)
|
72
75
|
if password
|
73
|
-
cipher.decrypt_block(password)
|
76
|
+
cipher.decrypt_block(password).gsub("\0", "")
|
74
77
|
else
|
75
78
|
password
|
76
79
|
end
|
@@ -180,7 +183,7 @@ module SmarterMeter
|
|
180
183
|
next if data.empty?
|
181
184
|
|
182
185
|
@ui.log.info("Verifying #{date}")
|
183
|
-
samples =
|
186
|
+
samples = Samples.parse_csv(data).values.first
|
184
187
|
first_sample = samples.first
|
185
188
|
|
186
189
|
if first_sample.kwh
|
@@ -207,7 +210,7 @@ module SmarterMeter
|
|
207
210
|
case @config[:transport]
|
208
211
|
when :google_powermeter
|
209
212
|
@ui.log.info("Uploading #{date} to Google PowerMeter")
|
210
|
-
transport = SmarterMeter::
|
213
|
+
transport = SmarterMeter::Services::GooglePowerMeter.new(@config[:google_powermeter])
|
211
214
|
if transport.upload(samples)
|
212
215
|
@ui.log.info("Upload for #{date} complete")
|
213
216
|
else
|
@@ -3,6 +3,7 @@ require 'profligacy/swing'
|
|
3
3
|
require 'profligacy/lel'
|
4
4
|
|
5
5
|
module SmarterMeter
|
6
|
+
# @private
|
6
7
|
module Interfaces
|
7
8
|
class Swing
|
8
9
|
include_package "java.awt"
|
@@ -147,6 +148,7 @@ module SmarterMeter
|
|
147
148
|
end
|
148
149
|
end
|
149
150
|
|
151
|
+
# @private
|
150
152
|
class Wizard
|
151
153
|
include_package "javax.swing"
|
152
154
|
include_package "java.awt"
|
data/lib/smartermeter/sample.rb
CHANGED
@@ -2,67 +2,40 @@ require 'date'
|
|
2
2
|
require 'time'
|
3
3
|
|
4
4
|
module SmarterMeter
|
5
|
+
# Represents a single hourly sample taken from the PG&E hourly electricity
|
6
|
+
# data. It's the most basic data unit of SmarterMeter.
|
5
7
|
class Sample
|
6
8
|
attr_accessor :time, :kwh
|
7
9
|
|
8
|
-
#
|
10
|
+
# Creates a new Sample.
|
9
11
|
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
def self.parse_csv(data)
|
14
|
-
samples = {}
|
15
|
-
date_re = /([0-9]{1,2})\/([0-9]{1,2})\/([0-9]{4})/
|
16
|
-
|
17
|
-
# Apparently they felt the need to put a = outside of the correct place
|
18
|
-
data = data.gsub('=','')
|
19
|
-
|
20
|
-
hour_increment = 60*60
|
21
|
-
CSV.parse(data) do |row|
|
22
|
-
next unless row.length > 0 and date_re.match row[0]
|
23
|
-
|
24
|
-
month, day, year = date_re.match(row[0]).captures
|
25
|
-
month = month.to_i
|
26
|
-
day = day.to_i
|
27
|
-
year = year.to_i
|
28
|
-
|
29
|
-
timestamp = Time.local(year, month, day, 0) - hour_increment
|
30
|
-
next if row[1].include? "$"
|
31
|
-
hourly_samples = row[1..24].map do |v|
|
32
|
-
if v == "-"
|
33
|
-
kwh = nil
|
34
|
-
else
|
35
|
-
kwh = v.to_f
|
36
|
-
end
|
37
|
-
|
38
|
-
timestamp = timestamp + hour_increment
|
39
|
-
Sample.new(timestamp, kwh)
|
40
|
-
end
|
41
|
-
samples[Date.new(year, month, day)] = hourly_samples
|
42
|
-
end
|
43
|
-
samples
|
44
|
-
end
|
45
|
-
|
12
|
+
# @param [Time] time the start of the sample period.
|
13
|
+
# @param [Float] kwh the number of killowatt hours used during the period of this sample.
|
14
|
+
# @return [Sample] the new Sample.
|
46
15
|
def initialize(time, kwh)
|
47
16
|
@time = time
|
48
17
|
@kwh = kwh
|
49
18
|
end
|
50
19
|
|
51
|
-
#
|
20
|
+
# The start time of this measurement in UTC.
|
52
21
|
#
|
53
|
-
#
|
22
|
+
# @return [String] the time in the format of 2011-01-06T09:00:00.000Z
|
54
23
|
def utc_start_time
|
55
24
|
@time.utc.strftime("%Y-%m-%dT%H:%M:%S.000Z")
|
56
25
|
end
|
57
26
|
|
58
|
-
#
|
59
|
-
# the start.
|
27
|
+
# The stop time of this measurement in UTC. It's assumed to be 1 hour after
|
28
|
+
# the start as that is the current resolution of PG&E's data.
|
60
29
|
#
|
61
|
-
#
|
30
|
+
# @return [String] the time in the format of 2011-01-06T09:00:00.000Z
|
62
31
|
def utc_stop_time
|
63
|
-
|
32
|
+
one_hour = 60*60
|
33
|
+
(@time + one_hour).utc.strftime("%Y-%m-%dT%H:%M:%S.000Z")
|
64
34
|
end
|
65
35
|
|
36
|
+
# Interrogates the current state of the Sample.
|
37
|
+
#
|
38
|
+
# Returns [String] a compact representation of the Sample.
|
66
39
|
def inspect
|
67
40
|
"<Sample #{@time} #{@kwh}>"
|
68
41
|
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'date'
|
2
|
+
require 'time'
|
3
|
+
|
4
|
+
module SmarterMeter
|
5
|
+
# Represents a collection of samples. In some cases it's useful to operate on
|
6
|
+
# groups of samples and this class provides that functionality.
|
7
|
+
class Samples < Hash
|
8
|
+
# Parses the CSV returned by PG&E and creates a Samples collection.
|
9
|
+
#
|
10
|
+
# @param [String] data the string containing the CSV returned by PG&E
|
11
|
+
# @return [Samples] creates a Samples collection from the given data.
|
12
|
+
def self.parse_csv(data)
|
13
|
+
samples = Samples.new
|
14
|
+
date_re = /([0-9]{1,2})\/([0-9]{1,2})\/([0-9]{4})/
|
15
|
+
|
16
|
+
# Apparently they felt the need to put a = outside of the correct place
|
17
|
+
data = data.gsub('=','')
|
18
|
+
|
19
|
+
hour_increment = 60*60
|
20
|
+
CSV.parse(data) do |row|
|
21
|
+
next unless row.length > 0 and date_re.match row[0]
|
22
|
+
|
23
|
+
month, day, year = date_re.match(row[0]).captures
|
24
|
+
month = month.to_i
|
25
|
+
day = day.to_i
|
26
|
+
year = year.to_i
|
27
|
+
|
28
|
+
timestamp = Time.local(year, month, day, 0) - hour_increment
|
29
|
+
next if row[1].include? "$"
|
30
|
+
hourly_samples = row[1..24].map do |v|
|
31
|
+
if v == "-"
|
32
|
+
kwh = nil
|
33
|
+
else
|
34
|
+
kwh = v.to_f
|
35
|
+
end
|
36
|
+
|
37
|
+
timestamp = timestamp + hour_increment
|
38
|
+
Sample.new(timestamp, kwh)
|
39
|
+
end
|
40
|
+
samples[Date.new(year, month, day)] = hourly_samples
|
41
|
+
end
|
42
|
+
samples
|
43
|
+
end
|
44
|
+
|
45
|
+
# Calculates the total number of kilowatt hours for all samples.
|
46
|
+
#
|
47
|
+
# @return [Float] the sum of kilowatt hours for all samples within this collection. If no samples are found 0 is returned.
|
48
|
+
def total_kwh
|
49
|
+
self.keys.reduce(0) { |sum, d| sum + total_kwh_on(d) }
|
50
|
+
end
|
51
|
+
|
52
|
+
# Calculates the total number of kilowatt hours
|
53
|
+
#
|
54
|
+
# @param [Date] date The date of the samples to include within the total.
|
55
|
+
#
|
56
|
+
# @return [Float] the sum of kilowatt hours for samples made of the given day. If none are found 0 is returned.
|
57
|
+
def total_kwh_on(date)
|
58
|
+
if self[date]
|
59
|
+
self[date].reduce(0) { |sum, s| sum + (s.kwh or 0) }
|
60
|
+
else
|
61
|
+
0
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
data/lib/smartermeter/service.rb
CHANGED
@@ -2,12 +2,21 @@ require 'mechanize'
|
|
2
2
|
require 'csv'
|
3
3
|
|
4
4
|
module SmarterMeter
|
5
|
+
# Provides access to the PG&E SmartMeter data through a ruby interface. This
|
6
|
+
# class depends on the PG&E website to function the same that it does today,
|
7
|
+
# so if something stops working its likely that something changed on PG&E's
|
8
|
+
# site and this class will need to be adapted.
|
5
9
|
class Service
|
6
10
|
LOGIN_URL = "http://www.pge.com/myhome/"
|
7
11
|
OVERVIEW_URL = "https://www.pge.com/csol/actions/login.do?aw"
|
8
12
|
ENERGYGUIDE_AUTH_URL = "https://www.energyguide.com/LoadAnalysis/LoadAnalysis.aspx?Referrerid=154"
|
9
13
|
|
14
|
+
# Provides access to the last page retrieved by mechanize. Useful for
|
15
|
+
# debugging and reporting errors.
|
10
16
|
attr_reader :last_page
|
17
|
+
|
18
|
+
# Provides access to the last exception thrown while accessing PG&E's site.
|
19
|
+
# Useful for debugging/error reporting.
|
11
20
|
attr_reader :last_exception
|
12
21
|
|
13
22
|
def initialize
|
@@ -16,7 +25,10 @@ module SmarterMeter
|
|
16
25
|
}
|
17
26
|
end
|
18
27
|
|
19
|
-
#
|
28
|
+
# Authenticates to the PG&E's website. Only needs to be performed once per
|
29
|
+
# instance of this class.
|
30
|
+
#
|
31
|
+
# @return [Boolean] true upon succesful login and false otherwise
|
20
32
|
def login(username, password)
|
21
33
|
begin
|
22
34
|
@agent.get(LOGIN_URL) do |page|
|
@@ -61,6 +73,15 @@ module SmarterMeter
|
|
61
73
|
end
|
62
74
|
end
|
63
75
|
|
76
|
+
# Downloads a CSV containing hourly date on that date. Up to a week worth
|
77
|
+
# of other data will be included depending on which day of the week that
|
78
|
+
# you request.
|
79
|
+
#
|
80
|
+
# PG&E compiles this data on a weekly schedule so if you ask for Monday
|
81
|
+
# you'll get the previous Sunday and the following days upto the next
|
82
|
+
# Sunday.
|
83
|
+
#
|
84
|
+
# @return [String] the CSV data.
|
64
85
|
def fetch_csv(date)
|
65
86
|
raise RuntimeException, "login must be called before fetch_csv" unless @authenticated
|
66
87
|
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'restclient'
|
2
|
+
require 'json'
|
3
|
+
require 'erb'
|
4
|
+
|
5
|
+
module SmarterMeter
|
6
|
+
module Services
|
7
|
+
# Allows users to calculate the carbon produced by their energy usage by
|
8
|
+
# accessing the Brighter Planet CM1 Electricity API.
|
9
|
+
#
|
10
|
+
# More details can be found here:
|
11
|
+
# http://carbon.brighterplanet.com/models/electricity_use
|
12
|
+
#
|
13
|
+
# Example:
|
14
|
+
# api = SmarterMeter::Services::BrighterPlanet.new
|
15
|
+
# puts api.calculate_kg_carbon(10.1)
|
16
|
+
#
|
17
|
+
# Prints:
|
18
|
+
# 0.6460529833458619
|
19
|
+
#
|
20
|
+
class BrighterPlanet
|
21
|
+
# The api key required for commericial access to the API. For more detail see:
|
22
|
+
# http://carbon.brighterplanet.com/pricing
|
23
|
+
attr_accessor :api_key
|
24
|
+
|
25
|
+
# Initializes the Brigher Planet CM1 Electricity API.
|
26
|
+
#
|
27
|
+
# Example:
|
28
|
+
#
|
29
|
+
# SmarterMeter::Services::BrighterPlanet.new do |c|
|
30
|
+
# c.api_key = "key"
|
31
|
+
# end
|
32
|
+
#
|
33
|
+
# @return [BrighterPlanet]
|
34
|
+
def initialize
|
35
|
+
yield self if block_given?
|
36
|
+
end
|
37
|
+
|
38
|
+
# Calculates the number of kilograms of carbon produced from the given
|
39
|
+
# electrical energy usage.
|
40
|
+
#
|
41
|
+
# Note: this is an estimate and depends on many factors, to improve
|
42
|
+
# accuracy include an optional zipcode of where this energy was consumed.
|
43
|
+
#
|
44
|
+
# @param [Float] kwh the number of kilowatt hours consumed.
|
45
|
+
# @params [Hash] opts can include `:zip_code` and/or `:date` to increase the accuracy of the estimate. `:date` should be in the following form: YYYY-MM-DD.
|
46
|
+
# @return [Float] kilograms of carbon produced by this much energy.
|
47
|
+
def calculate_kg_carbon(kwh, opts={})
|
48
|
+
allowed_keys = [:zip_code, :date]
|
49
|
+
non_permitted_keys = opts.keys.reject { |k| allowed_keys.include? k }
|
50
|
+
raise ArgumentError, "opts contains keys not found in #{allowed_keys}" unless non_permitted_keys.empty?
|
51
|
+
|
52
|
+
params = {:energy => kwh}
|
53
|
+
params.merge!(opts)
|
54
|
+
response = RestClient.get 'http://carbon.brighterplanet.com/electricity_uses.json', :params => params
|
55
|
+
JSON.parse(response.body)["emission"]
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
File without changes
|
File without changes
|
data/lib/smartermeter.rb
CHANGED
@@ -1,9 +1,11 @@
|
|
1
1
|
require 'smartermeter/sample'
|
2
|
+
require 'smartermeter/samples'
|
2
3
|
require 'smartermeter/service'
|
3
4
|
require 'smartermeter/daemon'
|
4
|
-
require 'smartermeter/
|
5
|
+
require 'smartermeter/services/google_powermeter'
|
6
|
+
require 'smartermeter/services/brighterplanet'
|
5
7
|
require 'smartermeter/interfaces/cli'
|
6
8
|
|
7
9
|
module SmarterMeter
|
8
|
-
VERSION = "0.3.
|
10
|
+
VERSION = "0.3.2"
|
9
11
|
end
|
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.3.
|
17
|
-
s.date = '2011-03-
|
16
|
+
s.version = '0.3.2'
|
17
|
+
s.date = '2011-03-29'
|
18
18
|
s.rubyforge_project = 'smartermeter'
|
19
19
|
|
20
20
|
## Make sure your summary is short. The description may be as long
|
@@ -49,11 +49,15 @@ Gem::Specification.new do |s|
|
|
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
51
|
s.add_dependency('mechanize', ["= 1.0.0"])
|
52
|
-
s.add_dependency('
|
52
|
+
s.add_dependency('crypt19', ["= 1.2.1"])
|
53
|
+
s.add_dependency('rest-client', ["= 1.6.1"])
|
54
|
+
s.add_dependency('json_pure', ["= 1.5.1"])
|
53
55
|
|
54
56
|
## List your development dependencies here. Development dependencies are
|
55
57
|
## those that are only needed during development
|
56
|
-
s.add_development_dependency('rspec', ["~> 2.
|
58
|
+
s.add_development_dependency('rspec', ["~> 2.5.0"])
|
59
|
+
s.add_development_dependency('vcr', ["~> 1.7.0"])
|
60
|
+
s.add_development_dependency('webmock', ["~> 1.6.2"])
|
57
61
|
s.add_development_dependency('minitar', ["~> 0.5.2"])
|
58
62
|
|
59
63
|
## Leave this section as-is. It will be automatically generated from the
|
@@ -79,21 +83,26 @@ Gem::Specification.new do |s|
|
|
79
83
|
lib/smartermeter/interfaces/cli.rb
|
80
84
|
lib/smartermeter/interfaces/swing.rb
|
81
85
|
lib/smartermeter/sample.rb
|
86
|
+
lib/smartermeter/samples.rb
|
82
87
|
lib/smartermeter/service.rb
|
83
|
-
lib/smartermeter/
|
84
|
-
lib/smartermeter/
|
85
|
-
lib/smartermeter/
|
88
|
+
lib/smartermeter/services/brighterplanet.rb
|
89
|
+
lib/smartermeter/services/cacert.pem
|
90
|
+
lib/smartermeter/services/google_powermeter.erb
|
91
|
+
lib/smartermeter/services/google_powermeter.rb
|
86
92
|
smartermeter.gemspec
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
+
spec/fixtures/data.csv
|
94
|
+
spec/fixtures/expected_google_request.xml
|
95
|
+
spec/fixtures/vcr_cassettes/brighterplanet.yml
|
96
|
+
spec/sample_spec.rb
|
97
|
+
spec/samples_spec.rb
|
98
|
+
spec/service_spec.rb
|
99
|
+
spec/services/brighterplanet_spec.rb
|
100
|
+
spec/services/google_powermeter_spec.rb
|
101
|
+
spec/spec_helper.rb
|
93
102
|
]
|
94
103
|
# = MANIFEST =
|
95
104
|
|
96
105
|
## Test files will be grabbed from the file list. Make sure the path glob
|
97
106
|
## matches what you actually use.
|
98
|
-
s.test_files = s.files.select { |path| path =~ /^
|
107
|
+
s.test_files = s.files.select { |path| path =~ /^spec\/*_spec.rb/ }
|
99
108
|
end
|
File without changes
|
File without changes
|
@@ -0,0 +1,106 @@
|
|
1
|
+
---
|
2
|
+
- !ruby/struct:VCR::HTTPInteraction
|
3
|
+
request: !ruby/struct:VCR::Request
|
4
|
+
method: :get
|
5
|
+
uri: http://carbon.brighterplanet.com:80/electricity_uses.json?energy=1
|
6
|
+
body:
|
7
|
+
headers:
|
8
|
+
accept:
|
9
|
+
- "*/*; q=0.5, application/xml"
|
10
|
+
accept-encoding:
|
11
|
+
- gzip, deflate
|
12
|
+
response: !ruby/struct:VCR::Response
|
13
|
+
status: !ruby/struct:VCR::ResponseStatus
|
14
|
+
code: 200
|
15
|
+
message: OK
|
16
|
+
headers:
|
17
|
+
server:
|
18
|
+
- nginx/0.6.35
|
19
|
+
date:
|
20
|
+
- Sat, 19 Mar 2011 18:49:12 GMT
|
21
|
+
content-type:
|
22
|
+
- application/json; charset=utf-8
|
23
|
+
transfer-encoding:
|
24
|
+
- chunked
|
25
|
+
status:
|
26
|
+
- 200 OK
|
27
|
+
etag:
|
28
|
+
- "\"f8891da38901f85f0b33fdd539c84199\""
|
29
|
+
cache-control:
|
30
|
+
- max-age=0, private, must-revalidate
|
31
|
+
x-ua-compatible:
|
32
|
+
- IE=Edge,chrome=1
|
33
|
+
x-runtime:
|
34
|
+
- "0.174617"
|
35
|
+
body: "{\"timeframe\":\"2011-01-01/2012-01-01\",\"emission\":0.6460529833458619,\"emission_units\":\"kilograms\",\"errors\":[],\"reports\":[{\"committee\":{\"name\":\"emission\",\"quorums\":[{\"name\":\"from date, emission factor, loss factor and energy\",\"requirements\":[\"date\",\"emission_factor\",\"loss_factor\",\"energy\"],\"appreciates\":[],\"complies\":[]}]},\"conclusion\":0.6460529833458619,\"quorum\":{\"name\":\"from date, emission factor, loss factor and energy\",\"requirements\":[\"date\",\"emission_factor\",\"loss_factor\",\"energy\"],\"appreciates\":[],\"complies\":[]}},{\"committee\":{\"name\":\"emission_factor\",\"quorums\":[{\"name\":\"from eGRID subregion\",\"requirements\":[\"egrid_subregion\"],\"appreciates\":[],\"complies\":[]}]},\"conclusion\":0.606076,\"quorum\":{\"name\":\"from eGRID subregion\",\"requirements\":[\"egrid_subregion\"],\"appreciates\":[],\"complies\":[]}},{\"committee\":{\"name\":\"loss_factor\",\"quorums\":[{\"name\":\"from eGRID region\",\"requirements\":[\"egrid_region\"],\"appreciates\":[],\"complies\":[]}]},\"conclusion\":0.0618788,\"quorum\":{\"name\":\"from eGRID region\",\"requirements\":[\"egrid_region\"],\"appreciates\":[],\"complies\":[]}},{\"committee\":{\"name\":\"egrid_region\",\"quorums\":[{\"name\":\"from eGRID subregion\",\"requirements\":[\"egrid_subregion\"],\"appreciates\":[],\"complies\":[]}]},\"conclusion\":{\"egrid_region\":{\"loss_factor\":0.0618788,\"name\":\"US\"}},\"quorum\":{\"name\":\"from eGRID subregion\",\"requirements\":[\"egrid_subregion\"],\"appreciates\":[],\"complies\":[]}},{\"committee\":{\"name\":\"egrid_subregion\",\"quorums\":[{\"name\":\"from zip code\",\"requirements\":[\"zip_code\"],\"appreciates\":[],\"complies\":[]},{\"name\":\"default\",\"requirements\":[],\"appreciates\":[],\"complies\":[]}]},\"conclusion\":{\"egrid_subregion\":{\"abbreviation\":\"US\",\"egrid_region_name\":\"US\",\"electricity_ch4_emission_factor\":0.000309198,\"electricity_ch4_emission_factor_units\":\"kilograms_co2e_per_kilowatt_hour\",\"electricity_co2_biogenic_emission_factor\":0.0,\"electricity_co2_biogenic_emission_factor_units\":\"kilograms_per_kilowatt_hour\",\"electricity_co2_emission_factor\":0.602982,\"electricity_co2_emission_factor_units\":\"kilograms_per_kilowatt_hour\",\"electricity_emission_factor\":0.606076,\"electricity_emission_factor_units\":\"kilograms_co2e_per_kilowatt_hour\",\"electricity_n2o_emission_factor\":0.00278485,\"electricity_n2o_emission_factor_units\":\"kilograms_co2e_per_kilowatt_hour\",\"name\":\"United States\",\"nerc_abbreviation\":\"US\",\"net_generation\":4056440000.0,\"net_generation_units\":\"megawatt_hours\"}},\"quorum\":{\"name\":\"default\",\"requirements\":[],\"appreciates\":[],\"complies\":[]}},{\"committee\":{\"name\":\"date\",\"quorums\":[{\"name\":\"from timeframe\",\"requirements\":[],\"appreciates\":[],\"complies\":[]}]},\"conclusion\":\"2011-01-01\",\"quorum\":{\"name\":\"from timeframe\",\"requirements\":[],\"appreciates\":[],\"complies\":[]}}],\"methodology\":\"http://carbon.brighterplanet.com/electricity_uses.html?energy=1&timeframe=2011-01-01%2F2012-01-01\",\"execution_id\":\"cd84d18a392c2782e8b0a114dd65a225184823a4be28aea4896d2d6c01d18dae959051b2a26b06b6\",\"compliance\":[],\"scope\":null,\"energy\":1.0,\"date\":\"2011-01-01\",\"egrid_subregion\":{\"egrid_subregion\":{\"abbreviation\":\"US\",\"egrid_region_name\":\"US\",\"electricity_ch4_emission_factor\":0.000309198,\"electricity_ch4_emission_factor_units\":\"kilograms_co2e_per_kilowatt_hour\",\"electricity_co2_biogenic_emission_factor\":0.0,\"electricity_co2_biogenic_emission_factor_units\":\"kilograms_per_kilowatt_hour\",\"electricity_co2_emission_factor\":0.602982,\"electricity_co2_emission_factor_units\":\"kilograms_per_kilowatt_hour\",\"electricity_emission_factor\":0.606076,\"electricity_emission_factor_units\":\"kilograms_co2e_per_kilowatt_hour\",\"electricity_n2o_emission_factor\":0.00278485,\"electricity_n2o_emission_factor_units\":\"kilograms_co2e_per_kilowatt_hour\",\"name\":\"United States\",\"nerc_abbreviation\":\"US\",\"net_generation\":4056440000.0,\"net_generation_units\":\"megawatt_hours\"}},\"egrid_region\":{\"egrid_region\":{\"loss_factor\":0.0618788,\"name\":\"US\"}},\"loss_factor\":0.0618788,\"emission_factor\":0.606076}"
|
36
|
+
http_version: "1.1"
|
37
|
+
- !ruby/struct:VCR::HTTPInteraction
|
38
|
+
request: !ruby/struct:VCR::Request
|
39
|
+
method: :get
|
40
|
+
uri: http://carbon.brighterplanet.com:80/electricity_uses.json?energy=1&zip_code=94110
|
41
|
+
body:
|
42
|
+
headers:
|
43
|
+
accept:
|
44
|
+
- "*/*; q=0.5, application/xml"
|
45
|
+
accept-encoding:
|
46
|
+
- gzip, deflate
|
47
|
+
response: !ruby/struct:VCR::Response
|
48
|
+
status: !ruby/struct:VCR::ResponseStatus
|
49
|
+
code: 200
|
50
|
+
message: OK
|
51
|
+
headers:
|
52
|
+
server:
|
53
|
+
- nginx/0.6.35
|
54
|
+
date:
|
55
|
+
- Sat, 19 Mar 2011 19:15:01 GMT
|
56
|
+
content-type:
|
57
|
+
- application/json; charset=utf-8
|
58
|
+
transfer-encoding:
|
59
|
+
- chunked
|
60
|
+
status:
|
61
|
+
- 200 OK
|
62
|
+
etag:
|
63
|
+
- "\"91afe2c319e60d06dd3b10f60c90a15d\""
|
64
|
+
cache-control:
|
65
|
+
- max-age=0, private, must-revalidate
|
66
|
+
x-ua-compatible:
|
67
|
+
- IE=Edge,chrome=1
|
68
|
+
x-runtime:
|
69
|
+
- "0.041468"
|
70
|
+
body: "{\"timeframe\":\"2011-01-01/2012-01-01\",\"emission\":0.3484751557886446,\"emission_units\":\"kilograms\",\"errors\":[],\"reports\":[{\"committee\":{\"name\":\"emission\",\"quorums\":[{\"name\":\"from date, emission factor, loss factor and energy\",\"requirements\":[\"date\",\"emission_factor\",\"loss_factor\",\"energy\"],\"appreciates\":[],\"complies\":[]}]},\"conclusion\":0.3484751557886446,\"quorum\":{\"name\":\"from date, emission factor, loss factor and energy\",\"requirements\":[\"date\",\"emission_factor\",\"loss_factor\",\"energy\"],\"appreciates\":[],\"complies\":[]}},{\"committee\":{\"name\":\"emission_factor\",\"quorums\":[{\"name\":\"from eGRID subregion\",\"requirements\":[\"egrid_subregion\"],\"appreciates\":[],\"complies\":[]}]},\"conclusion\":0.32989,\"quorum\":{\"name\":\"from eGRID subregion\",\"requirements\":[\"egrid_subregion\"],\"appreciates\":[],\"complies\":[]}},{\"committee\":{\"name\":\"loss_factor\",\"quorums\":[{\"name\":\"from eGRID region\",\"requirements\":[\"egrid_region\"],\"appreciates\":[],\"complies\":[]}]},\"conclusion\":0.0533328,\"quorum\":{\"name\":\"from eGRID region\",\"requirements\":[\"egrid_region\"],\"appreciates\":[],\"complies\":[]}},{\"committee\":{\"name\":\"egrid_region\",\"quorums\":[{\"name\":\"from eGRID subregion\",\"requirements\":[\"egrid_subregion\"],\"appreciates\":[],\"complies\":[]}]},\"conclusion\":{\"egrid_region\":{\"loss_factor\":0.0533328,\"name\":\"W\"}},\"quorum\":{\"name\":\"from eGRID subregion\",\"requirements\":[\"egrid_subregion\"],\"appreciates\":[],\"complies\":[]}},{\"committee\":{\"name\":\"egrid_subregion\",\"quorums\":[{\"name\":\"from zip code\",\"requirements\":[\"zip_code\"],\"appreciates\":[],\"complies\":[]},{\"name\":\"default\",\"requirements\":[],\"appreciates\":[],\"complies\":[]}]},\"conclusion\":{\"egrid_subregion\":{\"abbreviation\":\"CAMX\",\"egrid_region_name\":\"W\",\"electricity_ch4_emission_factor\":0.000342876,\"electricity_ch4_emission_factor_units\":\"kilograms_co2e_per_kilowatt_hour\",\"electricity_co2_biogenic_emission_factor\":0.0,\"electricity_co2_biogenic_emission_factor_units\":\"kilograms_per_kilowatt_hour\",\"electricity_co2_emission_factor\":0.328455,\"electricity_co2_emission_factor_units\":\"kilograms_per_kilowatt_hour\",\"electricity_emission_factor\":0.32989,\"electricity_emission_factor_units\":\"kilograms_co2e_per_kilowatt_hour\",\"electricity_n2o_emission_factor\":0.00109161,\"electricity_n2o_emission_factor_units\":\"kilograms_co2e_per_kilowatt_hour\",\"name\":\"WECC California\",\"nerc_abbreviation\":\"WECC\",\"net_generation\":219612000.0,\"net_generation_units\":\"megawatt_hours\"}},\"quorum\":{\"name\":\"from zip code\",\"requirements\":[\"zip_code\"],\"appreciates\":[],\"complies\":[]}},{\"committee\":{\"name\":\"date\",\"quorums\":[{\"name\":\"from timeframe\",\"requirements\":[],\"appreciates\":[],\"complies\":[]}]},\"conclusion\":\"2011-01-01\",\"quorum\":{\"name\":\"from timeframe\",\"requirements\":[],\"appreciates\":[],\"complies\":[]}}],\"methodology\":\"http://carbon.brighterplanet.com/electricity_uses.html?energy=1&timeframe=2011-01-01%2F2012-01-01&zip_code=94110\",\"execution_id\":\"863c7b45fcba5ba36bb2389f518b51be1665166db5f6a3c8d7ce3a3950c38d7e07d551fad2e7f4e7\",\"compliance\":[],\"scope\":null,\"energy\":1.0,\"zip_code\":{\"zip_code\":{\"climate_division_name\":\"CA4\",\"description\":\"San Francisco\",\"egrid_subregion_abbreviation\":\"CAMX\",\"latitude\":\"37.74873\",\"longitude\":\"-122.41545\",\"name\":\"94110\",\"state_postal_abbreviation\":\"CA\"}},\"date\":\"2011-01-01\",\"egrid_subregion\":{\"egrid_subregion\":{\"abbreviation\":\"CAMX\",\"egrid_region_name\":\"W\",\"electricity_ch4_emission_factor\":0.000342876,\"electricity_ch4_emission_factor_units\":\"kilograms_co2e_per_kilowatt_hour\",\"electricity_co2_biogenic_emission_factor\":0.0,\"electricity_co2_biogenic_emission_factor_units\":\"kilograms_per_kilowatt_hour\",\"electricity_co2_emission_factor\":0.328455,\"electricity_co2_emission_factor_units\":\"kilograms_per_kilowatt_hour\",\"electricity_emission_factor\":0.32989,\"electricity_emission_factor_units\":\"kilograms_co2e_per_kilowatt_hour\",\"electricity_n2o_emission_factor\":0.00109161,\"electricity_n2o_emission_factor_units\":\"kilograms_co2e_per_kilowatt_hour\",\"name\":\"WECC California\",\"nerc_abbreviation\":\"WECC\",\"net_generation\":219612000.0,\"net_generation_units\":\"megawatt_hours\"}},\"egrid_region\":{\"egrid_region\":{\"loss_factor\":0.0533328,\"name\":\"W\"}},\"loss_factor\":0.0533328,\"emission_factor\":0.32989}"
|
71
|
+
http_version: "1.1"
|
72
|
+
- !ruby/struct:VCR::HTTPInteraction
|
73
|
+
request: !ruby/struct:VCR::Request
|
74
|
+
method: :get
|
75
|
+
uri: http://carbon.brighterplanet.com:80/electricity_uses.json?date=2011-03-29&energy=1
|
76
|
+
body:
|
77
|
+
headers:
|
78
|
+
accept:
|
79
|
+
- "*/*; q=0.5, application/xml"
|
80
|
+
accept-encoding:
|
81
|
+
- gzip, deflate
|
82
|
+
response: !ruby/struct:VCR::Response
|
83
|
+
status: !ruby/struct:VCR::ResponseStatus
|
84
|
+
code: 200
|
85
|
+
message: OK
|
86
|
+
headers:
|
87
|
+
server:
|
88
|
+
- nginx/0.6.35
|
89
|
+
date:
|
90
|
+
- Tue, 29 Mar 2011 15:36:35 GMT
|
91
|
+
content-type:
|
92
|
+
- application/json; charset=utf-8
|
93
|
+
transfer-encoding:
|
94
|
+
- chunked
|
95
|
+
status:
|
96
|
+
- 200 OK
|
97
|
+
etag:
|
98
|
+
- "\"642c6acc898b96f4017bc27c2f321ee4\""
|
99
|
+
cache-control:
|
100
|
+
- max-age=0, private, must-revalidate
|
101
|
+
x-ua-compatible:
|
102
|
+
- IE=Edge,chrome=1
|
103
|
+
x-runtime:
|
104
|
+
- "0.026969"
|
105
|
+
body: "{\"timeframe\":\"2011-01-01/2012-01-01\",\"emission\":0.6460529833458619,\"emission_units\":\"kilograms\",\"errors\":[],\"reports\":[{\"committee\":{\"name\":\"emission\",\"quorums\":[{\"name\":\"from date, emission factor, loss factor and energy\",\"requirements\":[\"date\",\"emission_factor\",\"loss_factor\",\"energy\"],\"appreciates\":[],\"complies\":[]}]},\"conclusion\":0.6460529833458619,\"quorum\":{\"name\":\"from date, emission factor, loss factor and energy\",\"requirements\":[\"date\",\"emission_factor\",\"loss_factor\",\"energy\"],\"appreciates\":[],\"complies\":[]}},{\"committee\":{\"name\":\"emission_factor\",\"quorums\":[{\"name\":\"from eGRID subregion\",\"requirements\":[\"egrid_subregion\"],\"appreciates\":[],\"complies\":[]}]},\"conclusion\":0.606076,\"quorum\":{\"name\":\"from eGRID subregion\",\"requirements\":[\"egrid_subregion\"],\"appreciates\":[],\"complies\":[]}},{\"committee\":{\"name\":\"loss_factor\",\"quorums\":[{\"name\":\"from eGRID region\",\"requirements\":[\"egrid_region\"],\"appreciates\":[],\"complies\":[]}]},\"conclusion\":0.0618788,\"quorum\":{\"name\":\"from eGRID region\",\"requirements\":[\"egrid_region\"],\"appreciates\":[],\"complies\":[]}},{\"committee\":{\"name\":\"egrid_region\",\"quorums\":[{\"name\":\"from eGRID subregion\",\"requirements\":[\"egrid_subregion\"],\"appreciates\":[],\"complies\":[]}]},\"conclusion\":{\"egrid_region\":{\"loss_factor\":0.0618788,\"name\":\"US\"}},\"quorum\":{\"name\":\"from eGRID subregion\",\"requirements\":[\"egrid_subregion\"],\"appreciates\":[],\"complies\":[]}},{\"committee\":{\"name\":\"egrid_subregion\",\"quorums\":[{\"name\":\"from zip code\",\"requirements\":[\"zip_code\"],\"appreciates\":[],\"complies\":[]},{\"name\":\"default\",\"requirements\":[],\"appreciates\":[],\"complies\":[]}]},\"conclusion\":{\"egrid_subregion\":{\"abbreviation\":\"US\",\"egrid_region_name\":\"US\",\"electricity_ch4_emission_factor\":0.000309198,\"electricity_ch4_emission_factor_units\":\"kilograms_co2e_per_kilowatt_hour\",\"electricity_co2_biogenic_emission_factor\":0.0,\"electricity_co2_biogenic_emission_factor_units\":\"kilograms_per_kilowatt_hour\",\"electricity_co2_emission_factor\":0.602982,\"electricity_co2_emission_factor_units\":\"kilograms_per_kilowatt_hour\",\"electricity_emission_factor\":0.606076,\"electricity_emission_factor_units\":\"kilograms_co2e_per_kilowatt_hour\",\"electricity_n2o_emission_factor\":0.00278485,\"electricity_n2o_emission_factor_units\":\"kilograms_co2e_per_kilowatt_hour\",\"name\":\"United States\",\"nerc_abbreviation\":\"US\",\"net_generation\":4056440000.0,\"net_generation_units\":\"megawatt_hours\"}},\"quorum\":{\"name\":\"default\",\"requirements\":[],\"appreciates\":[],\"complies\":[]}}],\"methodology\":\"http://carbon.brighterplanet.com/electricity_uses.html?date=2011-03-29&energy=1&timeframe=2011-01-01%2F2012-01-01\",\"execution_id\":\"dec9aeca7a2b8750494fdd452337a4b6d8ca3649a7aebafce76d3976f91b0943e4669cf580a7a225\",\"compliance\":[],\"scope\":null,\"date\":\"2011-03-29\",\"energy\":1.0,\"egrid_subregion\":{\"egrid_subregion\":{\"abbreviation\":\"US\",\"egrid_region_name\":\"US\",\"electricity_ch4_emission_factor\":0.000309198,\"electricity_ch4_emission_factor_units\":\"kilograms_co2e_per_kilowatt_hour\",\"electricity_co2_biogenic_emission_factor\":0.0,\"electricity_co2_biogenic_emission_factor_units\":\"kilograms_per_kilowatt_hour\",\"electricity_co2_emission_factor\":0.602982,\"electricity_co2_emission_factor_units\":\"kilograms_per_kilowatt_hour\",\"electricity_emission_factor\":0.606076,\"electricity_emission_factor_units\":\"kilograms_co2e_per_kilowatt_hour\",\"electricity_n2o_emission_factor\":0.00278485,\"electricity_n2o_emission_factor_units\":\"kilograms_co2e_per_kilowatt_hour\",\"name\":\"United States\",\"nerc_abbreviation\":\"US\",\"net_generation\":4056440000.0,\"net_generation_units\":\"megawatt_hours\"}},\"egrid_region\":{\"egrid_region\":{\"loss_factor\":0.0618788,\"name\":\"US\"}},\"loss_factor\":0.0618788,\"emission_factor\":0.606076}"
|
106
|
+
http_version: "1.1"
|
data/spec/sample_spec.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe SmarterMeter::Samples do
|
4
|
+
before(:all) do
|
5
|
+
@data = File.read(File.join($FIXTURES_DIR, 'data.csv'))
|
6
|
+
@date_present = Date.new(2009, 9, 27)
|
7
|
+
end
|
8
|
+
|
9
|
+
subject { SmarterMeter::Samples.parse_csv(@data) }
|
10
|
+
|
11
|
+
it "can calculate the total number of kilowatt hours used" do
|
12
|
+
subject.total_kwh.should be_within(0.1).of(43.72)
|
13
|
+
end
|
14
|
+
|
15
|
+
it "can calculate the total number of kilowatt hours used on a specific day" do
|
16
|
+
subject.total_kwh_on(Date.new(2009, 9, 27)).should be_within(0.1).of(16.65)
|
17
|
+
end
|
18
|
+
|
19
|
+
it "can calculate the total number of kilowatt hours used on a day not given" do
|
20
|
+
subject.total_kwh_on(Date.new(2010, 9, 27)).should == 0
|
21
|
+
end
|
22
|
+
|
23
|
+
it "can access samples for a given day" do
|
24
|
+
subject.length.should == 7
|
25
|
+
subject.keys.should include(@date_present)
|
26
|
+
subject[@date_present].length.should == 24
|
27
|
+
subject[@date_present].each{|s| s.should be_kind_of(SmarterMeter::Sample)}
|
28
|
+
end
|
29
|
+
|
30
|
+
it "can handle an incomplete sample" do
|
31
|
+
subject[@date_present][0].kwh.should == nil
|
32
|
+
subject[@date_present][0].time.should == Time.local(2009, 9, 27, 0)
|
33
|
+
end
|
34
|
+
|
35
|
+
it "can handle a complete sample" do
|
36
|
+
subject[@date_present][1].kwh.should == 0.205
|
37
|
+
subject[@date_present][1].time.should == Time.local(2009, 9, 27, 1)
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
$:.unshift File.join(File.dirname(__FILE__), "..")
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe SmarterMeter::Services::BrighterPlanet do
|
5
|
+
it "can determine kilograms of carbon produced from the number of killowatt hours" do
|
6
|
+
VCR.use_cassette('brighterplanet', :record => :new_episodes) do
|
7
|
+
subject.calculate_kg_carbon(1).should be_within(0.1).of(0.64)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
it "can query for electricity from a specific zipcode" do
|
12
|
+
VCR.use_cassette('brighterplanet', :record => :new_episodes) do
|
13
|
+
subject.calculate_kg_carbon(1, :zip_code => "94110").should be_within(0.1).of(0.34)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
it "can query for electricity on a specific date" do
|
18
|
+
VCR.use_cassette('brighterplanet', :record => :new_episodes) do
|
19
|
+
subject.calculate_kg_carbon(1, :date => "2011-03-29").should be_within(0.1).of(0.64)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
it "doesn't allow electricity queries to include keys other than those specified" do
|
24
|
+
expect { subject.calculate_kg_carbon(1, :energy => 2) }.to raise_error(ArgumentError)
|
25
|
+
end
|
26
|
+
end
|
@@ -1,12 +1,12 @@
|
|
1
1
|
$:.unshift File.join(File.dirname(__FILE__), "..")
|
2
2
|
require 'spec_helper'
|
3
3
|
|
4
|
-
describe SmarterMeter::
|
4
|
+
describe SmarterMeter::Services::GooglePowerMeter do
|
5
5
|
before(:each) do
|
6
|
-
@subject = SmarterMeter::
|
7
|
-
|
6
|
+
@subject = SmarterMeter::Services::GooglePowerMeter.new(:token => "secret",
|
7
|
+
:variable => "/path")
|
8
8
|
data = File.read(File.join($FIXTURES_DIR, 'data.csv'))
|
9
|
-
@results = SmarterMeter::
|
9
|
+
@results = SmarterMeter::Samples.parse_csv(data)
|
10
10
|
end
|
11
11
|
|
12
12
|
it "can format a request for the API" do
|
@@ -2,8 +2,14 @@ require 'rubygems'
|
|
2
2
|
require 'bundler/setup'
|
3
3
|
Bundler.require(:default)
|
4
4
|
require 'rspec'
|
5
|
+
require 'vcr'
|
5
6
|
|
6
7
|
$:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
|
7
8
|
require 'smartermeter'
|
8
9
|
|
9
10
|
$FIXTURES_DIR = File.expand_path(File.join(File.dirname(__FILE__), "fixtures"))
|
11
|
+
|
12
|
+
VCR.config do |c|
|
13
|
+
c.cassette_library_dir = 'spec/fixtures/vcr_cassettes'
|
14
|
+
c.stub_with :webmock
|
15
|
+
end
|
metadata
CHANGED
@@ -1,12 +1,8 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: smartermeter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
prerelease:
|
5
|
-
|
6
|
-
- 0
|
7
|
-
- 3
|
8
|
-
- 1
|
9
|
-
version: 0.3.1
|
4
|
+
prerelease:
|
5
|
+
version: 0.3.2
|
10
6
|
platform: ruby
|
11
7
|
authors:
|
12
8
|
- Matt Colyer
|
@@ -14,65 +10,97 @@ autorequire:
|
|
14
10
|
bindir: bin
|
15
11
|
cert_chain: []
|
16
12
|
|
17
|
-
date: 2011-03-
|
13
|
+
date: 2011-03-29 00:00:00 -07:00
|
18
14
|
default_executable: smartermeter
|
19
15
|
dependencies:
|
20
16
|
- !ruby/object:Gem::Dependency
|
21
17
|
name: mechanize
|
22
18
|
prerelease: false
|
23
19
|
requirement: &id001 !ruby/object:Gem::Requirement
|
20
|
+
none: false
|
24
21
|
requirements:
|
25
22
|
- - "="
|
26
23
|
- !ruby/object:Gem::Version
|
27
|
-
segments:
|
28
|
-
- 1
|
29
|
-
- 0
|
30
|
-
- 0
|
31
24
|
version: 1.0.0
|
32
25
|
type: :runtime
|
33
26
|
version_requirements: *id001
|
34
27
|
- !ruby/object:Gem::Dependency
|
35
|
-
name:
|
28
|
+
name: crypt19
|
36
29
|
prerelease: false
|
37
30
|
requirement: &id002 !ruby/object:Gem::Requirement
|
31
|
+
none: false
|
38
32
|
requirements:
|
39
33
|
- - "="
|
40
34
|
- !ruby/object:Gem::Version
|
41
|
-
|
42
|
-
- 1
|
43
|
-
- 1
|
44
|
-
- 4
|
45
|
-
version: 1.1.4
|
35
|
+
version: 1.2.1
|
46
36
|
type: :runtime
|
47
37
|
version_requirements: *id002
|
48
38
|
- !ruby/object:Gem::Dependency
|
49
|
-
name:
|
39
|
+
name: rest-client
|
50
40
|
prerelease: false
|
51
41
|
requirement: &id003 !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - "="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: 1.6.1
|
47
|
+
type: :runtime
|
48
|
+
version_requirements: *id003
|
49
|
+
- !ruby/object:Gem::Dependency
|
50
|
+
name: json_pure
|
51
|
+
prerelease: false
|
52
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
53
|
+
none: false
|
54
|
+
requirements:
|
55
|
+
- - "="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: 1.5.1
|
58
|
+
type: :runtime
|
59
|
+
version_requirements: *id004
|
60
|
+
- !ruby/object:Gem::Dependency
|
61
|
+
name: rspec
|
62
|
+
prerelease: false
|
63
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
64
|
+
none: false
|
52
65
|
requirements:
|
53
66
|
- - ~>
|
54
67
|
- !ruby/object:Gem::Version
|
55
|
-
|
56
|
-
- 2
|
57
|
-
- 4
|
58
|
-
- 0
|
59
|
-
version: 2.4.0
|
68
|
+
version: 2.5.0
|
60
69
|
type: :development
|
61
|
-
version_requirements: *
|
70
|
+
version_requirements: *id005
|
71
|
+
- !ruby/object:Gem::Dependency
|
72
|
+
name: vcr
|
73
|
+
prerelease: false
|
74
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
75
|
+
none: false
|
76
|
+
requirements:
|
77
|
+
- - ~>
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: 1.7.0
|
80
|
+
type: :development
|
81
|
+
version_requirements: *id006
|
82
|
+
- !ruby/object:Gem::Dependency
|
83
|
+
name: webmock
|
84
|
+
prerelease: false
|
85
|
+
requirement: &id007 !ruby/object:Gem::Requirement
|
86
|
+
none: false
|
87
|
+
requirements:
|
88
|
+
- - ~>
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: 1.6.2
|
91
|
+
type: :development
|
92
|
+
version_requirements: *id007
|
62
93
|
- !ruby/object:Gem::Dependency
|
63
94
|
name: minitar
|
64
95
|
prerelease: false
|
65
|
-
requirement: &
|
96
|
+
requirement: &id008 !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
66
98
|
requirements:
|
67
99
|
- - ~>
|
68
100
|
- !ruby/object:Gem::Version
|
69
|
-
segments:
|
70
|
-
- 0
|
71
|
-
- 5
|
72
|
-
- 2
|
73
101
|
version: 0.5.2
|
74
102
|
type: :development
|
75
|
-
version_requirements: *
|
103
|
+
version_requirements: *id008
|
76
104
|
description: Fetches SmartMeter data from PG&E and can upload to Google PowerMeter
|
77
105
|
email: matt.removethis@nospam.colyer.name
|
78
106
|
executables:
|
@@ -100,17 +128,22 @@ files:
|
|
100
128
|
- lib/smartermeter/interfaces/cli.rb
|
101
129
|
- lib/smartermeter/interfaces/swing.rb
|
102
130
|
- lib/smartermeter/sample.rb
|
131
|
+
- lib/smartermeter/samples.rb
|
103
132
|
- lib/smartermeter/service.rb
|
104
|
-
- lib/smartermeter/
|
105
|
-
- lib/smartermeter/
|
106
|
-
- lib/smartermeter/
|
133
|
+
- lib/smartermeter/services/brighterplanet.rb
|
134
|
+
- lib/smartermeter/services/cacert.pem
|
135
|
+
- lib/smartermeter/services/google_powermeter.erb
|
136
|
+
- lib/smartermeter/services/google_powermeter.rb
|
107
137
|
- smartermeter.gemspec
|
108
|
-
-
|
109
|
-
-
|
110
|
-
-
|
111
|
-
-
|
112
|
-
-
|
113
|
-
-
|
138
|
+
- spec/fixtures/data.csv
|
139
|
+
- spec/fixtures/expected_google_request.xml
|
140
|
+
- spec/fixtures/vcr_cassettes/brighterplanet.yml
|
141
|
+
- spec/sample_spec.rb
|
142
|
+
- spec/samples_spec.rb
|
143
|
+
- spec/service_spec.rb
|
144
|
+
- spec/services/brighterplanet_spec.rb
|
145
|
+
- spec/services/google_powermeter_spec.rb
|
146
|
+
- spec/spec_helper.rb
|
114
147
|
has_rdoc: true
|
115
148
|
homepage: http://github.com/mcolyer/smartermeter
|
116
149
|
licenses: []
|
@@ -121,23 +154,21 @@ rdoc_options: []
|
|
121
154
|
require_paths:
|
122
155
|
- lib
|
123
156
|
required_ruby_version: !ruby/object:Gem::Requirement
|
157
|
+
none: false
|
124
158
|
requirements:
|
125
159
|
- - ">="
|
126
160
|
- !ruby/object:Gem::Version
|
127
|
-
segments:
|
128
|
-
- 0
|
129
161
|
version: "0"
|
130
162
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
163
|
+
none: false
|
131
164
|
requirements:
|
132
165
|
- - ">="
|
133
166
|
- !ruby/object:Gem::Version
|
134
|
-
segments:
|
135
|
-
- 0
|
136
167
|
version: "0"
|
137
168
|
requirements: []
|
138
169
|
|
139
170
|
rubyforge_project: smartermeter
|
140
|
-
rubygems_version: 1.
|
171
|
+
rubygems_version: 1.5.0
|
141
172
|
signing_key:
|
142
173
|
specification_version: 2
|
143
174
|
summary: Fetches SmartMeter data from PG&E
|
data/specs/sample_spec.rb
DELETED
@@ -1,24 +0,0 @@
|
|
1
|
-
$:.unshift File.join(File.dirname(__FILE__))
|
2
|
-
require 'spec_helper'
|
3
|
-
|
4
|
-
describe SmarterMeter::Sample do
|
5
|
-
before(:all) do
|
6
|
-
@data = File.read(File.join($FIXTURES_DIR, 'data.csv'))
|
7
|
-
end
|
8
|
-
|
9
|
-
it "should be able to parse csv data returned by the api" do
|
10
|
-
date = Date.new(2009, 9, 27)
|
11
|
-
results = SmarterMeter::Sample.parse_csv(@data)
|
12
|
-
|
13
|
-
results.length.should == 7
|
14
|
-
results.keys.should include(date)
|
15
|
-
results[date].length.should == 24
|
16
|
-
results[date].each{|s| s.should be_kind_of(SmarterMeter::Sample)}
|
17
|
-
|
18
|
-
results[date][0].kwh.should == nil
|
19
|
-
results[date][0].time.should == Time.local(2009, 9, 27, 0)
|
20
|
-
|
21
|
-
results[date][1].kwh.should == 0.205
|
22
|
-
results[date][1].time.should == Time.local(2009, 9, 27, 1)
|
23
|
-
end
|
24
|
-
end
|