green-button-data 0.6.0 → 0.7.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.
- checksums.yaml +8 -8
- data/.codeclimate.yml +5 -0
- data/.gitignore +1 -1
- data/Gemfile.lock +100 -0
- data/README.md +2 -2
- data/green-button-data.gemspec +1 -1
- data/lib/green-button-data/client.rb +61 -0
- data/lib/green-button-data/configuration.rb +14 -1
- data/lib/green-button-data/entry.rb +1 -1
- data/lib/green-button-data/fetchable.rb +68 -48
- data/lib/green-button-data/parser/cost_additional_detail_last_period.rb +4 -0
- data/lib/green-button-data/version.rb +1 -1
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
NjFhMDE3MzUwYzQ3ZmJhOWE3MThiZmJlM2VlMjZhMGY2MzU5Yzc0Nw==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
OTE2MWUzNDI1YjRiOTQ0ZWZkZWIxNTQxYzE1YzEyZTQ0YzU2NGFhZA==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
Y2ZmODJhOWJkNTgwOTc5NWFhOWIyZmU3ZDI1YjFjMjAwNzQ2NDY0NDQyYmY4
|
10
|
+
ZTMwZmJjMTAxNzIwYzM0NTA4YWFmYWJlM2U3YjQ3MmRjNGY4NTU1NDRhMTgy
|
11
|
+
NjY1MzdlYTdiNGEwOTJhZDdiZWU1MmI1MTI3NjNiZWZlYjA4NDE=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
YmQyZWQ0ZmRmNDYzNjEzZjg0Mzc0ZGIxNmJmNThlMWIwYjJlMzFhOGFmYjRm
|
14
|
+
Zjg4MmFjODhlYzE1ZmJlM2E1YzJmMDU5ZThmNTY1OGY4MmExOTUyMDM4Mjcy
|
15
|
+
MzU2MmQ2NjllNjRmMTk1NjBkNzAxNWRiMTgwODk1NDc5MmNjOWI=
|
data/.codeclimate.yml
ADDED
data/.gitignore
CHANGED
data/Gemfile.lock
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
green-button-data (0.6.0)
|
5
|
+
faraday (~> 0.9)
|
6
|
+
nokogiri (~> 1.6)
|
7
|
+
sax-machine (~> 1.3)
|
8
|
+
|
9
|
+
GEM
|
10
|
+
remote: https://rubygems.org/
|
11
|
+
specs:
|
12
|
+
addressable (2.3.8)
|
13
|
+
codecov (0.1.0)
|
14
|
+
json
|
15
|
+
simplecov
|
16
|
+
url
|
17
|
+
coderay (1.1.0)
|
18
|
+
crack (0.4.2)
|
19
|
+
safe_yaml (~> 1.0.0)
|
20
|
+
diff-lcs (1.2.5)
|
21
|
+
docile (1.1.5)
|
22
|
+
faraday (0.9.2)
|
23
|
+
multipart-post (>= 1.2, < 3)
|
24
|
+
ffi (1.9.10)
|
25
|
+
formatador (0.2.5)
|
26
|
+
guard (2.13.0)
|
27
|
+
formatador (>= 0.2.4)
|
28
|
+
listen (>= 2.7, <= 4.0)
|
29
|
+
lumberjack (~> 1.0)
|
30
|
+
nenv (~> 0.1)
|
31
|
+
notiffany (~> 0.0)
|
32
|
+
pry (>= 0.9.12)
|
33
|
+
shellany (~> 0.0)
|
34
|
+
thor (>= 0.18.1)
|
35
|
+
guard-compat (1.2.1)
|
36
|
+
guard-rspec (4.5.0)
|
37
|
+
guard (~> 2.1)
|
38
|
+
guard-compat (~> 1.1)
|
39
|
+
rspec (>= 2.99.0, < 4.0)
|
40
|
+
json (1.8.3)
|
41
|
+
listen (3.0.3)
|
42
|
+
rb-fsevent (>= 0.9.3)
|
43
|
+
rb-inotify (>= 0.9)
|
44
|
+
lumberjack (1.0.9)
|
45
|
+
method_source (0.8.2)
|
46
|
+
mini_portile2 (2.1.0)
|
47
|
+
multipart-post (2.0.0)
|
48
|
+
nenv (0.2.0)
|
49
|
+
nokogiri (1.6.8)
|
50
|
+
mini_portile2 (~> 2.1.0)
|
51
|
+
pkg-config (~> 1.1.7)
|
52
|
+
notiffany (0.0.7)
|
53
|
+
nenv (~> 0.1)
|
54
|
+
shellany (~> 0.0)
|
55
|
+
pkg-config (1.1.7)
|
56
|
+
pry (0.10.1)
|
57
|
+
coderay (~> 1.1.0)
|
58
|
+
method_source (~> 0.8.1)
|
59
|
+
slop (~> 3.4)
|
60
|
+
rb-fsevent (0.9.5)
|
61
|
+
rb-inotify (0.9.5)
|
62
|
+
ffi (>= 0.5.0)
|
63
|
+
rspec (3.3.0)
|
64
|
+
rspec-core (~> 3.3.0)
|
65
|
+
rspec-expectations (~> 3.3.0)
|
66
|
+
rspec-mocks (~> 3.3.0)
|
67
|
+
rspec-core (3.3.2)
|
68
|
+
rspec-support (~> 3.3.0)
|
69
|
+
rspec-expectations (3.3.1)
|
70
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
71
|
+
rspec-support (~> 3.3.0)
|
72
|
+
rspec-mocks (3.3.2)
|
73
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
74
|
+
rspec-support (~> 3.3.0)
|
75
|
+
rspec-support (3.3.0)
|
76
|
+
safe_yaml (1.0.4)
|
77
|
+
sax-machine (1.3.2)
|
78
|
+
shellany (0.0.1)
|
79
|
+
simplecov (0.10.0)
|
80
|
+
docile (~> 1.1.0)
|
81
|
+
json (~> 1.8)
|
82
|
+
simplecov-html (~> 0.10.0)
|
83
|
+
simplecov-html (0.10.0)
|
84
|
+
slop (3.6.0)
|
85
|
+
thor (0.19.1)
|
86
|
+
url (0.3.2)
|
87
|
+
webmock (1.21.0)
|
88
|
+
addressable (>= 2.3.6)
|
89
|
+
crack (>= 0.3.2)
|
90
|
+
|
91
|
+
PLATFORMS
|
92
|
+
ruby
|
93
|
+
|
94
|
+
DEPENDENCIES
|
95
|
+
codecov
|
96
|
+
green-button-data!
|
97
|
+
guard (~> 2.13)
|
98
|
+
guard-rspec
|
99
|
+
rspec (~> 3.0)
|
100
|
+
webmock (~> 1.21)
|
data/README.md
CHANGED
@@ -108,8 +108,8 @@ ESPI Green Button Data reference API and the other for Pacific Gas & Electric:
|
|
108
108
|
|
109
109
|
```ruby
|
110
110
|
espi_base_url = "https://services.greenbuttondata.org/DataCustodian/espi/" +
|
111
|
-
"1_1/
|
112
|
-
pge_base_url = "https://api.pge.com/GreenButtonConnect/espi/1_1/
|
111
|
+
"1_1/resource/"
|
112
|
+
pge_base_url = "https://api.pge.com/GreenButtonConnect/espi/1_1/resource/"
|
113
113
|
|
114
114
|
espi_client = GreenButtonData.connect base_url: "https://foo.com" do |client|
|
115
115
|
# Override base_url configuration
|
data/green-button-data.gemspec
CHANGED
@@ -4,7 +4,7 @@ Gem::Specification.new do |s|
|
|
4
4
|
s.name = 'green-button-data'
|
5
5
|
s.version = GreenButtonData::VERSION
|
6
6
|
|
7
|
-
s.authors = ['Andrew Jo']
|
7
|
+
s.authors = ['Andrew Jo', 'Orlando Lee']
|
8
8
|
s.email = 'engineering@verdigris.co'
|
9
9
|
s.homepage = 'http://verdigris.co'
|
10
10
|
s.licenses = ['BSD-2-Clause']
|
@@ -192,6 +192,66 @@ module GreenButtonData
|
|
192
192
|
)
|
193
193
|
end
|
194
194
|
|
195
|
+
def interval_block_bulk(id = nil, options = {})
|
196
|
+
if id.is_a? Hash
|
197
|
+
options = id
|
198
|
+
id = nil
|
199
|
+
end
|
200
|
+
|
201
|
+
subscription_id = options[:subscription_id]
|
202
|
+
bulk_file_id = options[:bulk_file_id]
|
203
|
+
|
204
|
+
get_resource(
|
205
|
+
@configuration.bulk_url(
|
206
|
+
subscription_id: subscription_id,
|
207
|
+
bulk_file_id: bulk_file_id
|
208
|
+
),
|
209
|
+
id,
|
210
|
+
IntervalBlock,
|
211
|
+
sanitize_options(options)
|
212
|
+
)
|
213
|
+
end
|
214
|
+
|
215
|
+
def usage_summary_bulk(id = nil, options = {})
|
216
|
+
if id.is_a? Hash
|
217
|
+
options = id
|
218
|
+
id = nil
|
219
|
+
end
|
220
|
+
|
221
|
+
subscription_id = options[:subscription_id]
|
222
|
+
bulk_file_id = options[:bulk_file_id]
|
223
|
+
|
224
|
+
get_resource(
|
225
|
+
@configuration.bulk_url(
|
226
|
+
subscription_id: subscription_id,
|
227
|
+
bulk_file_id: bulk_file_id
|
228
|
+
),
|
229
|
+
id,
|
230
|
+
UsageSummary,
|
231
|
+
sanitize_options(options)
|
232
|
+
)
|
233
|
+
end
|
234
|
+
|
235
|
+
def retail_customer_bulk(id = nil, options = {})
|
236
|
+
if id.is_a? Hash
|
237
|
+
options = id
|
238
|
+
id = nil
|
239
|
+
end
|
240
|
+
|
241
|
+
subscription_id = options[:subscription_id]
|
242
|
+
bulk_file_id = options[:bulk_file_id]
|
243
|
+
|
244
|
+
get_resource(
|
245
|
+
@configuration.bulk_url(
|
246
|
+
subscription_id: subscription_id,
|
247
|
+
bulk_file_id: bulk_file_id
|
248
|
+
),
|
249
|
+
id,
|
250
|
+
RetailCustomer,
|
251
|
+
sanitize_options(options)
|
252
|
+
)
|
253
|
+
end
|
254
|
+
|
195
255
|
private
|
196
256
|
|
197
257
|
def get_resource(url, id = nil, klazz = nil, options = {})
|
@@ -214,6 +274,7 @@ module GreenButtonData
|
|
214
274
|
options.delete(:subscription_id) if options.has_key? :subscription_id
|
215
275
|
options.delete(:usage_point_id) if options.has_key? :usage_point_id
|
216
276
|
options.delete(:usage_summary_id) if options.has_key? :usage_summary_id
|
277
|
+
options.delete(:bulk_file_id) if options.has_key? :bulk_file_id
|
217
278
|
options
|
218
279
|
end
|
219
280
|
end
|
@@ -12,7 +12,8 @@ module GreenButtonData
|
|
12
12
|
:subscription_path,
|
13
13
|
:usage_point_path,
|
14
14
|
:usage_summary_path,
|
15
|
-
:retail_customer_path
|
15
|
+
:retail_customer_path,
|
16
|
+
:bulk_path
|
16
17
|
|
17
18
|
def application_information_url(id = nil)
|
18
19
|
return build_url @application_information_path, id
|
@@ -137,6 +138,18 @@ module GreenButtonData
|
|
137
138
|
end
|
138
139
|
end
|
139
140
|
|
141
|
+
def bulk_url(kwargs = {})
|
142
|
+
subscription_id = kwargs[:subscription_id]
|
143
|
+
bulk_file_id = kwargs[:bulk_file_id]
|
144
|
+
|
145
|
+
if subscription_id && bulk_file_id
|
146
|
+
bulk_url = build_url(@bulk_path)
|
147
|
+
return "#{bulk_url}/#{subscription_id}/#{bulk_file_id}"
|
148
|
+
else
|
149
|
+
raise ArgumentError.new "Missing required arguments: subscription_id or bulk_file_id"
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
140
153
|
private
|
141
154
|
|
142
155
|
def build_url(path, id = nil)
|
@@ -140,64 +140,83 @@ module GreenButtonData
|
|
140
140
|
self.name.split('::').last
|
141
141
|
end
|
142
142
|
|
143
|
-
def
|
144
|
-
|
143
|
+
def resource_from_url(url)
|
144
|
+
# Matches resource name in URL (e.g. ApplicationInformation)
|
145
|
+
resource = '([a-zA-Z]+)'
|
145
146
|
|
146
|
-
|
147
|
-
|
148
|
-
|
147
|
+
# Matches Base 64 encoded resource ID used by PG&E for MeterReading
|
148
|
+
# resource identifier
|
149
|
+
base64_id = '\w+=*'
|
150
|
+
|
151
|
+
# Matches numeric ID with thousands separator in commas used for
|
152
|
+
# UsageSummary IDs for PG&E endpoints but also matches traditional
|
153
|
+
# digits without comma separator
|
154
|
+
num_id = '(\d+,*\d*)+'
|
155
|
+
|
156
|
+
# Matches GUID as the resource ID used mainly by PG&E for
|
157
|
+
# ApplicationInformation resource identifier
|
158
|
+
guid = '[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}' +
|
159
|
+
'-[0-9A-Fa-f]{12}'
|
160
|
+
|
161
|
+
# Identifier can be any of the above patterns
|
162
|
+
identifier = "(#{base64_id}|#{num_id}|#{guid})"
|
163
|
+
|
164
|
+
/\/(#{resource}|#{resource}\/#{identifier})\/*\z/.match(url)
|
165
|
+
end
|
166
|
+
|
167
|
+
def usage_point_id_from_url(url)
|
168
|
+
usage_point = 'UsagePoint\/(.*?)\/'
|
169
|
+
/(#{usage_point})/.match(url)
|
170
|
+
end
|
149
171
|
|
150
|
-
|
151
|
-
|
152
|
-
|
172
|
+
def valid_resources
|
173
|
+
[
|
174
|
+
'applicationinformation',
|
175
|
+
'authorization',
|
176
|
+
'electricpowerusagesummary',
|
177
|
+
'intervalblock',
|
178
|
+
'localtimeparameters',
|
179
|
+
'readingtype',
|
180
|
+
'usagepoint',
|
181
|
+
'usagesummary',
|
182
|
+
'servicelocation',
|
183
|
+
'customeragreement'
|
184
|
+
]
|
185
|
+
end
|
153
186
|
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
num_id = '(\d+,*\d*)+'
|
187
|
+
def valid_resource?(resource)
|
188
|
+
resource.downcase =~ /(#{valid_resources.join('|')})/
|
189
|
+
end
|
158
190
|
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
191
|
+
def type_match_class?(type)
|
192
|
+
class_name_mapping = {
|
193
|
+
'ServiceLocation' => 'RetailCustomer',
|
194
|
+
'CustomerAgreement' => 'RetailCustomer',
|
195
|
+
'ElectricPowerUsageSummary' => 'UsageSummary'
|
196
|
+
}
|
197
|
+
type == class_name || (class_name_mapping.has_key?(type) && class_name_mapping[type] == class_name)
|
198
|
+
end
|
199
|
+
|
200
|
+
def infer_content_from(entry, resource)
|
201
|
+
return nil unless valid_resource? resource
|
202
|
+
entry.content.send resource.underscore
|
203
|
+
end
|
163
204
|
|
164
|
-
|
165
|
-
|
205
|
+
def each_entry_content(feed)
|
206
|
+
entry_content = nil
|
166
207
|
|
167
|
-
|
168
|
-
|
208
|
+
feed.entries.each do |entry|
|
209
|
+
match_data = resource_from_url(entry.self)
|
169
210
|
|
170
211
|
unless match_data.nil?
|
171
212
|
id = match_data[4] || entry.id
|
172
213
|
type = match_data[2] || match_data[3]
|
214
|
+
next unless type_match_class?(type)
|
173
215
|
|
174
|
-
entry_content =
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
when 'authorization'
|
179
|
-
entry.content.authorization
|
180
|
-
when 'electricpowerusagesummary'
|
181
|
-
entry.content.electric_power_usage_summary
|
182
|
-
when 'intervalblock'
|
183
|
-
entry.content.interval_block
|
184
|
-
when 'localtimeparameters'
|
185
|
-
entry.content.local_time_parameters
|
186
|
-
when 'readingtype'
|
187
|
-
entry.content.reading_type
|
188
|
-
when 'usagepoint'
|
189
|
-
entry.content.usage_point
|
190
|
-
when 'usagesummary'
|
191
|
-
entry.content.usage_summary
|
192
|
-
when 'servicelocation'
|
193
|
-
entry.content.service_location
|
194
|
-
when 'customeragreement'
|
195
|
-
entry.content.customer_agreement
|
196
|
-
else
|
197
|
-
nil
|
198
|
-
end
|
199
|
-
|
200
|
-
yield id, entry_content, entry
|
216
|
+
entry_content = infer_content_from entry, type
|
217
|
+
match_usage_point_id = usage_point_id_from_url(entry.self)
|
218
|
+
usage_point_id = match_usage_point_id[2] unless match_usage_point_id.nil?
|
219
|
+
yield id, entry_content, entry, usage_point_id
|
201
220
|
end
|
202
221
|
end
|
203
222
|
end
|
@@ -205,9 +224,10 @@ module GreenButtonData
|
|
205
224
|
def populate_models(feed)
|
206
225
|
models = GreenButtonData::ModelCollection.new
|
207
226
|
|
208
|
-
each_entry_content feed do |id, content, entry|
|
227
|
+
each_entry_content feed do |id, content, entry, usage_point_id|
|
209
228
|
attributes_hash = attributes_to_hash(content)
|
210
229
|
attributes_hash[:id] = id
|
230
|
+
attributes_hash[:usage_point_id] = usage_point_id
|
211
231
|
|
212
232
|
attributes_hash[:related_urls] = construct_related_urls entry
|
213
233
|
models << self.new(attributes_hash)
|
@@ -3,6 +3,7 @@ module GreenButtonData
|
|
3
3
|
class CostAdditionalDetailLastPeriod < SummaryMeasurement
|
4
4
|
element :note
|
5
5
|
element :itemKind, class: Integer, as: :item_kind
|
6
|
+
element :amount, class: Integer, as: :amount
|
6
7
|
|
7
8
|
# ESPI Namespacing
|
8
9
|
element :'espi:note', as: :note
|
@@ -11,6 +12,9 @@ module GreenButtonData
|
|
11
12
|
# Special case for PG&E generic namespacing
|
12
13
|
element :'ns0:note', as: :note
|
13
14
|
element :'ns0:itemKind', class: Integer, as: :item_kind
|
15
|
+
|
16
|
+
# Special case for SCE generic namespacing
|
17
|
+
element :'ns0:amount', class: Integer, as: :amount
|
14
18
|
end
|
15
19
|
end
|
16
20
|
end
|
metadata
CHANGED
@@ -1,14 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: green-button-data
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrew Jo
|
8
|
+
- Orlando Lee
|
8
9
|
autorequire:
|
9
10
|
bindir: bin
|
10
11
|
cert_chain: []
|
11
|
-
date: 2016-
|
12
|
+
date: 2016-09-29 00:00:00.000000000 Z
|
12
13
|
dependencies:
|
13
14
|
- !ruby/object:Gem::Dependency
|
14
15
|
name: nokogiri
|
@@ -102,9 +103,11 @@ executables: []
|
|
102
103
|
extensions: []
|
103
104
|
extra_rdoc_files: []
|
104
105
|
files:
|
106
|
+
- .codeclimate.yml
|
105
107
|
- .gitignore
|
106
108
|
- .rspec
|
107
109
|
- Gemfile
|
110
|
+
- Gemfile.lock
|
108
111
|
- Guardfile
|
109
112
|
- LICENSE.txt
|
110
113
|
- README.md
|