aemo 0.1.14 → 0.1.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 55b1d416d39ba3d49361f5ee2f3d024f60d56820
4
- data.tar.gz: 95c401f11e4b3786a1ca242c23a86f83c25ffe1a
3
+ metadata.gz: bfdc14964d912d1e5fa19f8d00bbcd36968d3d65
4
+ data.tar.gz: 5864b68a25e24bdbea94fcc3eebb4bd76fccc4cd
5
5
  SHA512:
6
- metadata.gz: 5e6dcf774f34e228c0bd0484fc06b0ee8eba5b60a8adb42c217699cdd1947afd927be87e3a70ce227f69cab8fdd0b6f34ed2da2c0cc523bccd27f33a1e42a809
7
- data.tar.gz: 2b992ea03bb9656a194fd297d97ee77b253528f71d94d4005b71fbbbe77024b4ca3111f9504dbe24a3be718236718dc824d135fc13b7f7aa12537ad063165822
6
+ metadata.gz: 31b1ae761b24d6e72d8f0b27e5f193549810365f0e3ea71ba7c514cc200407afb818ff7dfeda14e28014eb7ef6d81cd78686b5ee65d0096a46eb1b26ccf4ecb7
7
+ data.tar.gz: 10b305008ce90bfd3080b393c80e9e5e761f008d578a7588f9bb5ff6e10958ef53546a382285e80eae87ca19e48e9b2be61464557be5ab9f443e501fe75d4815
data/.gitignore CHANGED
@@ -3,4 +3,5 @@
3
3
  # Don't include gems in the repository
4
4
  *.gem
5
5
  # Or documentation
6
- .yardoc/
6
+ .yardoc/
7
+ .env
data/Gemfile CHANGED
@@ -1,19 +1,21 @@
1
- source "http://rubygems.org"
2
- # Add dependencies required to use your gem here.
3
- # Example:
4
- # gem "activesupport", ">= 2.3.5"
1
+ source "https://rubygems.org" do
2
+ # Add dependencies required to use your gem here.
3
+ # Example:
4
+ # gem "activesupport", ">= 2.3.5"
5
5
 
6
- gem 'httparty', '~0.13'
7
- gem 'json', '~1.8'
8
- gem 'multi_xml', '>= 0.5.2'
9
- gem 'coveralls', :require => false
6
+ gem 'httparty', '~>0.13'
7
+ gem 'json', '~>1.8'
8
+ gem 'multi_xml', '>= 0.5.2'
9
+ gem 'coveralls', :require => false
10
+ gem 'zip'
10
11
 
11
- # Add dependencies to develop your gem here.
12
- # Include everything needed to run rake, tests, features, etc.
13
- # group :development do
14
- # gem "shoulda", ">= 0"
15
- # gem "rdoc", "~> 3.12"
16
- # gem "bundler", ">= 1.0.0"
17
- # gem "jeweler", ">= 1.8.4"
18
- # gem "simplecov", ">= 0"
19
- # end
12
+ # Add dependencies to develop your gem here.
13
+ # Include everything needed to run rake, tests, features, etc.
14
+ group :development do
15
+ gem "rspec", ">= 0"
16
+ gem "rdoc", "~> 3.12"
17
+ gem "bundler", ">= 1.0.0"
18
+ gem "jeweler", ">= 1.8.4"
19
+ gem "simplecov", ">= 0"
20
+ end
21
+ end
data/Gemfile.lock CHANGED
@@ -1,7 +1,113 @@
1
1
  GEM
2
+ remote: https://rubygems.org/
2
3
  specs:
4
+ addressable (2.3.8)
5
+ builder (3.2.2)
6
+ coveralls (0.8.2)
7
+ json (~> 1.8)
8
+ rest-client (>= 1.6.8, < 2)
9
+ simplecov (~> 0.10.0)
10
+ term-ansicolor (~> 1.3)
11
+ thor (~> 0.19.1)
12
+ descendants_tracker (0.0.4)
13
+ thread_safe (~> 0.3, >= 0.3.1)
14
+ diff-lcs (1.2.5)
15
+ docile (1.1.5)
16
+ domain_name (0.5.24)
17
+ unf (>= 0.0.5, < 1.0.0)
18
+ faraday (0.9.1)
19
+ multipart-post (>= 1.2, < 3)
20
+ git (1.2.9.1)
21
+ github_api (0.12.4)
22
+ addressable (~> 2.3)
23
+ descendants_tracker (~> 0.0.4)
24
+ faraday (~> 0.8, < 0.10)
25
+ hashie (>= 3.4)
26
+ multi_json (>= 1.7.5, < 2.0)
27
+ nokogiri (~> 1.6.6)
28
+ oauth2
29
+ hashie (3.4.2)
30
+ highline (1.7.3)
31
+ http-cookie (1.0.2)
32
+ domain_name (~> 0.5)
33
+ httparty (0.13.5)
34
+ json (~> 1.8)
35
+ multi_xml (>= 0.5.2)
36
+ jeweler (2.0.1)
37
+ builder
38
+ bundler (>= 1.0)
39
+ git (>= 1.2.5)
40
+ github_api
41
+ highline (>= 1.6.15)
42
+ nokogiri (>= 1.5.10)
43
+ rake
44
+ rdoc
45
+ json (1.8.3)
46
+ jwt (1.5.1)
47
+ mime-types (2.6.1)
48
+ mini_portile (0.6.2)
49
+ multi_json (1.11.2)
50
+ multi_xml (0.5.5)
51
+ multipart-post (2.0.0)
52
+ netrc (0.10.3)
53
+ nokogiri (1.6.6.2)
54
+ mini_portile (~> 0.6.0)
55
+ oauth2 (1.0.0)
56
+ faraday (>= 0.8, < 0.10)
57
+ jwt (~> 1.0)
58
+ multi_json (~> 1.3)
59
+ multi_xml (~> 0.5)
60
+ rack (~> 1.2)
61
+ rack (1.6.4)
62
+ rake (10.4.2)
63
+ rdoc (3.12.2)
64
+ json (~> 1.4)
65
+ rest-client (1.8.0)
66
+ http-cookie (>= 1.0.2, < 2.0)
67
+ mime-types (>= 1.16, < 3.0)
68
+ netrc (~> 0.7)
69
+ rspec (3.3.0)
70
+ rspec-core (~> 3.3.0)
71
+ rspec-expectations (~> 3.3.0)
72
+ rspec-mocks (~> 3.3.0)
73
+ rspec-core (3.3.2)
74
+ rspec-support (~> 3.3.0)
75
+ rspec-expectations (3.3.1)
76
+ diff-lcs (>= 1.2.0, < 2.0)
77
+ rspec-support (~> 3.3.0)
78
+ rspec-mocks (3.3.2)
79
+ diff-lcs (>= 1.2.0, < 2.0)
80
+ rspec-support (~> 3.3.0)
81
+ rspec-support (3.3.0)
82
+ simplecov (0.10.0)
83
+ docile (~> 1.1.0)
84
+ json (~> 1.8)
85
+ simplecov-html (~> 0.10.0)
86
+ simplecov-html (0.10.0)
87
+ term-ansicolor (1.3.2)
88
+ tins (~> 1.0)
89
+ thor (0.19.1)
90
+ thread_safe (0.3.5)
91
+ tins (1.5.4)
92
+ unf (0.1.4)
93
+ unf_ext
94
+ unf_ext (0.0.7.1)
95
+ zip (2.0.2)
3
96
 
4
97
  PLATFORMS
5
98
  ruby
6
99
 
7
100
  DEPENDENCIES
101
+ bundler (>= 1.0.0)!
102
+ coveralls!
103
+ httparty (~> 0.13)!
104
+ jeweler (>= 1.8.4)!
105
+ json (~> 1.8)!
106
+ multi_xml (>= 0.5.2)!
107
+ rdoc (~> 3.12)!
108
+ rspec!
109
+ simplecov!
110
+ zip!
111
+
112
+ BUNDLED WITH
113
+ 1.10.3
data/aemo.gemspec CHANGED
@@ -1,26 +1,29 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
  $:.push File.expand_path('../lib', __FILE__)
3
+ require 'aemo/version'
3
4
 
4
5
  Gem::Specification.new do |s|
5
6
  s.name = 'aemo'
6
- s.version = '0.1.14'
7
+ s.version = AEMO::VERSION
7
8
  s.platform = Gem::Platform::RUBY
8
- s.date = '2015-03-23'
9
+ s.date = '2015-08-27'
9
10
  s.summary = 'AEMO Gem'
10
11
  s.description = 'Gem providing functionality for the Australian Energy Market Operator data'
11
- s.authors = ['Joel Courtney']
12
- s.email = ['jcourtney@cozero.com.au']
12
+ s.authors = ['Joel Courtney','Stuart Auld']
13
+ s.email = ['jcourtney@cozero.com.au','sauld@cozero.com.au']
13
14
  s.homepage = 'https://github.com/jufemaiz/aemo'
14
15
  s.license = 'MIT'
15
-
16
+
16
17
  s.required_ruby_version = '>= 1.9.3'
17
18
 
18
19
  s.add_dependency 'json', '~> 1.8'
20
+ s.add_dependency 'nokogiri', '~> 1.6', '>= 1.6.6'
21
+ s.add_dependency 'zip', '~>2.0'
19
22
  s.add_runtime_dependency 'multi_xml', '~> 0.5', '>= 0.5.2'
20
- s.add_runtime_dependency 'httparty', '~> 0.13', '>= 0.13.1'
23
+ s.add_runtime_dependency 'httparty', '~> 0.13', '>= 0.13.1'
21
24
 
22
25
  s.files = `git ls-files`.split("\n")
23
26
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
24
27
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
25
28
  s.require_paths = ['lib']
26
- end
29
+ end
data/lib/aemo/msats.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  require 'httparty'
2
2
  require 'aemo'
3
- require 'zip'
3
+ # require 'zip'
4
4
  require 'nokogiri'
5
5
  require 'digest/sha1'
6
6
 
@@ -18,22 +18,21 @@ module AEMO
18
18
  include HTTParty
19
19
  # We like to debug
20
20
  # debug_output $stdout
21
-
21
+
22
22
  # We like to SSLv3
23
23
  ssl_version :SSLv3
24
24
 
25
25
  # Where we like to party
26
26
  base_uri 'https://msats.prod.nemnet.net.au/msats/ws/'
27
-
27
+
28
28
  def initialize(options = {})
29
29
  @@auth = {username: nil, password: nil}
30
- @retailer = 'COZEROER'
31
30
 
32
31
  @@auth[:username] = options[:username] if options[:username].is_a?(String)
33
32
  @@auth[:password] = options[:password] if options[:password].is_a?(String)
34
33
  @@participant_id = options[:participant_id] if options[:participant_id].is_a?(String)
35
34
  end
36
-
35
+
37
36
  # Single NMI Master (C4) Report
38
37
  # /C4/PARTICIPANT_IDENTIFIER?transactionId=XXX&nmi=XXX&checksum=X&type=XXX&reason=XXX
39
38
  #
@@ -51,10 +50,10 @@ module AEMO
51
50
  options[:participantId] ||= nil
52
51
  options[:roleId] ||= nil
53
52
  options[:inittransId] ||= nil
54
-
53
+
55
54
  query = {
56
55
  transactionId: Digest::SHA1.hexdigest(Time.now.to_s)[0..35],
57
- NMI: nmi.nmi, # Note: AEMO is a bunch of idiots, has case sensitivity but no consistency across requests. Muppets.
56
+ NMI: nmi.nmi, # Note: AEMO has case sensitivity but no consistency across requests.
58
57
  fromDate: from_date,
59
58
  toDate: to_date,
60
59
  asatDate: as_at_date,
@@ -62,9 +61,13 @@ module AEMO
62
61
  roleId: options[:role_id],
63
62
  inittransId: options[:init_trans_id],
64
63
  }
65
-
66
- response = self.get( "/C4/#{@@participant_id}", basic_auth: @@auth, headers: { 'Accept' => 'text/xml', 'Content-Type' => 'text/xml'}, query: query )
67
- response.parsed_response['aseXML']['Transactions']['Transaction']['ReportResponse']['ReportResults']
64
+
65
+ response = self.get( "/C4/#{@@participant_id}", basic_auth: @@auth, headers: { 'Accept' => 'text/xml', 'Content-Type' => 'text/xml'}, query: query )
66
+ if response.response.code != '200'
67
+ response
68
+ else
69
+ response.parsed_response['aseXML']['Transactions']['Transaction']['ReportResponse']['ReportResults']
70
+ end
68
71
  end
69
72
 
70
73
  # MSATS Limits
@@ -76,27 +79,35 @@ module AEMO
76
79
  transactionId: Digest::SHA1.hexdigest(Time.now.to_s)[0..35],
77
80
  }
78
81
  response = self.get( "/MSATSLimits/#{@@participant_id}", basic_auth: @@auth, headers: { 'Accept' => 'text/xml', 'Content-Type' => 'text/xml'}, query: query )
79
- response.parsed_response['aseXML']['Transactions']['Transaction']['ReportResponse']['ReportResults']
82
+ if response.response.code != '200'
83
+ response
84
+ else
85
+ response.parsed_response['aseXML']['Transactions']['Transaction']['ReportResponse']['ReportResults']
86
+ end
80
87
  end
81
-
88
+
82
89
  # NMI Discovery - By Delivery Point Identifier
83
90
  #
84
91
  # @param [String] jurisdiction_code The Jurisdiction Code
85
- # @param [Integer] delivery_point_identifier Delivery Point Iddentifier
92
+ # @param [Integer] delivery_point_identifier Delivery Point Identifier
86
93
  # @return [Hash] The response
87
94
  def self.nmi_discovery_by_delivery_point_identifier(jurisdiction_code,delivery_point_identifier)
88
95
  raise ArgumentError, 'jurisdiction_code is not valid' unless %w(ACT NEM NSW QLD SA VIC TAS).include?(jurisdiction_code)
89
96
  raise ArgumentError, 'delivery_point_identifier is not valid' unless delivery_point_identifier.respond_to?("to_i")
90
97
  raise ArgumentError, 'delivery_point_identifier is not valid' if( delivery_point_identifier.to_i < 10000000 || delivery_point_identifier.to_i > 99999999)
91
-
98
+
92
99
  query = {
93
100
  transactionId: Digest::SHA1.hexdigest(Time.now.to_s)[0..35],
94
101
  jurisdictionCode: jurisdiction_code,
95
102
  deliveryPointIdentifier: delivery_point_identifier.to_i
96
103
  }
97
-
104
+
98
105
  response = self.get( "/NMIDiscovery/#{@@participant_id}", basic_auth: @@auth, headers: { 'Accept' => 'text/xml', 'Content-Type' => 'text/xml'}, query: query )
99
- response.parsed_response['aseXML']['Transactions']['Transaction']['NMIDiscoveryResponse']['NMIStandingData']
106
+ if response.response.code != '200'
107
+ response
108
+ else
109
+ response.parsed_response['aseXML']['Transactions']['Transaction']['NMIDiscoveryResponse']['NMIStandingData']
110
+ end
100
111
  end
101
112
 
102
113
  # NMI Discovery - By Meter Serial Numner
@@ -106,15 +117,19 @@ module AEMO
106
117
  # @return [Hash] The response
107
118
  def self.nmi_discovery_by_meter_serial_number(jurisdiction_code,meter_serial_number)
108
119
  raise ArgumentError, 'jurisdiction_code is not valid' unless %w(ACT NEM NSW QLD SA VIC TAS).include?(jurisdiction_code)
109
-
120
+
110
121
  query = {
111
122
  transactionId: Digest::SHA1.hexdigest(Time.now.to_s)[0..35],
112
123
  jurisdictionCode: jurisdiction_code,
113
124
  meterSerialNumber: meter_serial_number.to_i
114
125
  }
115
-
126
+
116
127
  response = self.get( "/NMIDiscovery/#{@@participant_id}", basic_auth: @@auth, headers: { 'Accept' => 'text/xml', 'Content-Type' => 'text/xml'}, query: query )
117
- response.parsed_response['aseXML']['Transactions']['Transaction']['NMIDiscoveryResponse']['NMIStandingData']
128
+ if response.response.code != '200'
129
+ response
130
+ else
131
+ response.parsed_response['aseXML']['Transactions']['Transaction']['NMIDiscoveryResponse']['NMIStandingData']
132
+ end
118
133
  end
119
134
 
120
135
  # NMI Discovery - By Address
@@ -124,7 +139,7 @@ module AEMO
124
139
  # @return [Hash] The response
125
140
  def self.nmi_discovery_by_address(jurisdiction_code,options = {})
126
141
  raise ArgumentError, 'jurisdiction_code is not valid' unless %w(ACT NEM NSW QLD SA VIC TAS).include?(jurisdiction_code)
127
-
142
+
128
143
  options[:building_or_property_name] ||= nil
129
144
  options[:location_descriptor] ||= nil
130
145
  options[:lot_number] ||= nil
@@ -140,7 +155,7 @@ module AEMO
140
155
  options[:suburb_or_place_or_locality] ||= nil
141
156
  options[:postcode] ||= nil
142
157
  options[:state_or_territory] ||= jurisdiction_code
143
-
158
+
144
159
  query = {
145
160
  transactionId: Digest::SHA1.hexdigest(Time.now.to_s)[0..35],
146
161
  jurisdictionCode: jurisdiction_code,
@@ -160,9 +175,14 @@ module AEMO
160
175
  postcode: options[:postcode],
161
176
  stateOrTerritory: options[:state_or_territory]
162
177
  }
163
-
178
+
164
179
  response = self.get( "/NMIDiscovery/#{@@participant_id}", basic_auth: @@auth, headers: { 'Accept' => 'text/xml', 'Content-Type' => 'text/xml'}, query: query )
165
- response.parsed_response['aseXML']['Transactions']['Transaction']['NMIDiscoveryResponse']['NMIStandingData']
180
+ if response.response.code != '200'
181
+ response
182
+ else
183
+ myresponse = response.parsed_response['aseXML']['Transactions']['Transaction']['NMIDiscoveryResponse']['NMIStandingData']
184
+ myresponse.is_a?(Hash)? [ myresponse ] : myresponse
185
+ end
166
186
  end
167
187
 
168
188
  # NMI Detail
@@ -175,7 +195,7 @@ module AEMO
175
195
  end
176
196
  options[:type] ||= nil
177
197
  options[:reason] ||= nil
178
-
198
+
179
199
  query = {
180
200
  transactionId: Digest::SHA1.hexdigest(Time.now.to_s)[0..35],
181
201
  nmi: nmi.nmi,
@@ -183,11 +203,15 @@ module AEMO
183
203
  type: options[:type],
184
204
  reason: options[:reason]
185
205
  }
186
-
206
+
187
207
  response = self.get( "/NMIDetail/#{@@participant_id}", basic_auth: @@auth, headers: { 'Accept' => 'text/xml', 'Content-Type' => 'text/xml'}, query: query )
188
- response.parsed_response['aseXML']['Transactions']['Transaction']['NMIStandingDataResponse']['NMIStandingData']
208
+ if response.response.code != '200'
209
+ response
210
+ else
211
+ response.parsed_response['aseXML']['Transactions']['Transaction']['NMIStandingDataResponse']['NMIStandingData']
212
+ end
189
213
  end
190
-
214
+
191
215
  # Participant System Status
192
216
  # /ParticipantSystemStatus/PARTICIPANT_IDENTIFIER?transactionId=XXX
193
217
  #
@@ -197,10 +221,14 @@ module AEMO
197
221
  transactionId: Digest::SHA1.hexdigest(Time.now.to_s)[0..35],
198
222
  }
199
223
  response = self.get( "/ParticipantSystemStatus/#{@@participant_id}", basic_auth: @@auth, headers: { 'Accept' => 'text/xml', 'Content-Type' => 'text/xml'}, query: query )
200
- response.parsed_response['aseXML']['Transactions']['Transaction']['ReportResponse']['ReportResults']
224
+ if response.response.code != '200'
225
+ response
226
+ else
227
+ response.parsed_response['aseXML']['Transactions']['Transaction']['ReportResponse']['ReportResults']
228
+ end
201
229
  end
202
-
203
-
230
+
231
+
204
232
  # Sets the authentication credentials in a class variable.
205
233
  #
206
234
  # @param [String] email cl.ly email
@@ -210,13 +238,13 @@ module AEMO
210
238
  @@participant_id = participant_id
211
239
  @@auth = {username: username, password: password}
212
240
  end
213
-
241
+
214
242
  # Check if credentials are available to use
215
243
  #
216
244
  # @return [Boolean] true/false if credentials are available
217
245
  def self.can_authenticate?
218
246
  !(@@participant_id.nil? || @@auth[:username].nil? || @@auth[:username].nil?)
219
247
  end
220
-
248
+
221
249
  end
222
250
  end
data/lib/aemo/nem12.rb CHANGED
@@ -12,7 +12,7 @@ module AEMO
12
12
  500 => 'B2B Details',
13
13
  900 => 'End'
14
14
  }
15
-
15
+
16
16
  TRANSACTION_CODE_FLAGS = {
17
17
  'A' => 'Alteration',
18
18
  'C' => 'Meter Reconfiguration',
@@ -24,7 +24,7 @@ module AEMO
24
24
  'S' => 'Special Read',
25
25
  'R' => 'Removal of Meter'
26
26
  }
27
-
27
+
28
28
  UOM = {
29
29
  'MWh' => { :name => 'Megawatt Hour', :multiplier => 1e6 },
30
30
  'kWh' => { :name => 'Kilowatt Hour', :multiplier => 1e3 },
@@ -50,7 +50,7 @@ module AEMO
50
50
  'A' => { :name => 'Ampere', :multiplier => 1 },
51
51
  'pf' => { :name => 'Power Factor', :multiplier => 1 }
52
52
  }
53
-
53
+
54
54
  UOM_NON_SPEC_MAPPING = {
55
55
  'MWH' => 'MWh',
56
56
  'KWH' => 'kWh',
@@ -76,7 +76,7 @@ module AEMO
76
76
  'A' => 'A',
77
77
  'PF' => 'pf'
78
78
  }
79
-
79
+
80
80
  QUALITY_FLAGS = {
81
81
  'A' => 'Actual Data',
82
82
  'E' => 'Forward Estimated Data',
@@ -85,7 +85,7 @@ module AEMO
85
85
  'S' => 'Substituted Data',
86
86
  'V' => 'Variable Data',
87
87
  }
88
-
88
+
89
89
  METHOD_FLAGS = {
90
90
  11 => { type: ["SUB"], installation_type: [1,2,3,4], short_descriptor: "Check", description: "" },
91
91
  12 => { type: ["SUB"], installation_type: [1,2,3,4], short_descriptor: "Calculated", description: "" },
@@ -118,7 +118,7 @@ module AEMO
118
118
  74 => { type: ["SUB"], installation_type: 7, short_descriptor: "Agreed", description: "" },
119
119
  75 => { type: ["EST"], installation_type: 7, short_descriptor: "Existing Table", description: "" }
120
120
  }
121
-
121
+
122
122
  REASON_CODES = {
123
123
  0 => 'Free Text Description',
124
124
  1 => 'Meter/Equipment Changed',
@@ -220,9 +220,9 @@ module AEMO
220
220
  97 => 'Excluded Data',
221
221
  98 => 'Parity Error',
222
222
  99 => 'Energy Type (Register Changed)'
223
-
223
+
224
224
  }
225
-
225
+
226
226
  DATA_STREAM_SUFFIX = {
227
227
  # Averaged Data Streams
228
228
  'A' => { :stream => 'Average', :description => 'Import', :units => 'kWh' },
@@ -250,18 +250,19 @@ module AEMO
250
250
  'W' => { :stream => 'Check', :description => 'Par Metering Path', :units => '' },
251
251
  'Z' => { :stream => 'Check', :description => 'Volts or V2h or Amps or A2h', :units => '' },
252
252
  # Net Meter Streams
253
- 'D' => { :stream => 'Net', :description => 'Net', :units => 'kWh' },
254
- 'J' => { :stream => 'Net', :description => 'Net', :units => 'kVArh' }
253
+ # AEMO: NOTE THAT D AND J ARE PREVIOUSLY DEFINED
254
+ # 'D' => { :stream => 'Net', :description => 'Net', :units => 'kWh' },
255
+ # 'J' => { :stream => 'Net', :description => 'Net', :units => 'kVArh' }
255
256
  }
256
-
257
+
257
258
  @nmi = nil
258
259
  @data_details = []
259
260
  @interval_data = []
260
261
  @interval_events = []
261
-
262
+
262
263
  attr_accessor :nmi, :file_contents
263
264
  attr_reader :data_details, :interval_data, :interval_events
264
-
265
+
265
266
  # Initialize a NEM12 file
266
267
  def initialize(nmi,options={})
267
268
  @nmi = nmi
@@ -272,7 +273,7 @@ module AEMO
272
273
  eval "self.#{key} = #{options[key]}"
273
274
  end
274
275
  end
275
-
276
+
276
277
  # @return [Integer] checksum of the NMI
277
278
  def nmi_checksum
278
279
  summation = 0
@@ -283,7 +284,7 @@ module AEMO
283
284
  end
284
285
  value = value.to_s.split(//).map{|i| i.to_i}.reduce(:+)
285
286
  summation += value
286
- end
287
+ end
287
288
  checksum = (10 - (summation % 10)) % 10
288
289
  checksum
289
290
  end
@@ -310,7 +311,7 @@ module AEMO
310
311
  :to_participant => csv[4]
311
312
  }
312
313
  end
313
-
314
+
314
315
  # Parses the NMI Data Details
315
316
  # @param line [String] A single line in string format
316
317
  # @return [Hash] the line parsed into a hash of information
@@ -334,7 +335,7 @@ module AEMO
334
335
  raise ArgumentError, 'UOM is not valid' unless UOM.keys.map{|k| k.upcase}.include?(csv[7].upcase)
335
336
  raise ArgumentError, 'IntervalLength is not valid' unless %w(1 5 10 15 30).include?(csv[8])
336
337
  # raise ArgumentError, 'NextScheduledReadDate is not valid' if csv[9].match(/\d{8}/).nil? || csv[9] != Time.parse("#{csv[9]}").strftime('%Y%m%d')
337
-
338
+
338
339
  @nmi = csv[1]
339
340
 
340
341
  # Push onto the stack
@@ -351,7 +352,7 @@ module AEMO
351
352
  :next_scheduled_read_date => csv[9],
352
353
  }
353
354
  end
354
-
355
+
355
356
  # @param line [String] A single line in string format
356
357
  # @return [Array of hashes] the line parsed into a hash of information
357
358
  def parse_nem12_300(line,options={})
@@ -360,7 +361,7 @@ module AEMO
360
361
  raise TypeError, 'Expected NMI Data Details to exist with IntervalLength specified' if @data_details.last.nil? || @data_details.last[:interval_length].nil?
361
362
  number_of_intervals = 1440 / @data_details.last[:interval_length]
362
363
  intervals_offset = number_of_intervals + 2
363
-
364
+
364
365
  raise ArgumentError, 'RecordIndicator is not 300' if csv[0] != '300'
365
366
  raise ArgumentError, 'IntervalDate is not valid' if csv[1].match(/\d{8}/).nil? || csv[1] != Time.parse("#{csv[1]}").strftime('%Y%m%d')
366
367
  (2..(number_of_intervals+1)).each do |i|
@@ -385,7 +386,7 @@ module AEMO
385
386
  raise ArgumentError, 'MSATSLoadDateTime is not valid' if csv[intervals_offset + 4].match(/\d{14}/).nil? || csv[intervals_offset + 4] != Time.parse("#{csv[intervals_offset + 4]}").strftime('%Y%m%d%H%M%S')
386
387
  end
387
388
  end
388
-
389
+
389
390
  # Deal with flags if necessary
390
391
  flag = nil
391
392
  # Based on QualityMethod and ReasonCode
@@ -399,7 +400,7 @@ module AEMO
399
400
  flag[:reason_code] = csv[intervals_offset + 1].to_i
400
401
  end
401
402
  end
402
-
403
+
403
404
  base_interval = { data_details: @data_details.last, datetime: Time.parse("#{csv[1]}000000+1000"), value: nil, flag: flag}
404
405
 
405
406
  intervals = []
@@ -412,7 +413,7 @@ module AEMO
412
413
  @interval_data += intervals
413
414
  intervals
414
415
  end
415
-
416
+
416
417
  # @param line [String] A single line in string format
417
418
  # @return [Hash] the line parsed into a hash of information
418
419
  def parse_nem12_400(line)
@@ -423,14 +424,14 @@ module AEMO
423
424
  raise ArgumentError, 'QualityMethod is not valid' if csv[3].match(/^([AN]|([AEFNSV]\d{2}))$/).nil?
424
425
  # raise ArgumentError, 'ReasonCode is not valid' if (csv[4].nil? && csv[3].match(/^ANE/)) || csv[4].match(/^\d{3}?$/) || csv[3].match(/^ANE/)
425
426
  # raise ArgumentError, 'ReasonDescription is not valid' if (csv[4].nil? && csv[3].match(/^ANE/)) || ( csv[5].match(/^$/) && csv[4].match(/^0$/) )
426
-
427
+
427
428
  interval_events = []
428
-
429
+
429
430
  # Only need to update flags for EFSV
430
431
  unless %w(A N).include?csv[3]
431
432
  number_of_intervals = 1440 / @data_details.last[:interval_length]
432
433
  interval_start_point = @interval_data.length - number_of_intervals
433
-
434
+
434
435
  # For each of these
435
436
  base_interval_event = { datetime: nil, quality_method: csv[3], reason_code: (csv[4].nil? ? nil : csv[4].to_i), reason_description: csv[5] }
436
437
 
@@ -455,17 +456,17 @@ module AEMO
455
456
  end
456
457
  interval_events
457
458
  end
458
-
459
+
459
460
  # @param line [String] A single line in string format
460
461
  # @return [Hash] the line parsed into a hash of information
461
462
  def parse_nem12_500(line,options={})
462
463
  end
463
-
464
+
464
465
  # @param line [String] A single line in string format
465
466
  # @return [Hash] the line parsed into a hash of information
466
467
  def parse_nem12_900(line,options={})
467
468
  end
468
-
469
+
469
470
  # Turns the flag to a string
470
471
  #
471
472
  # @param [Hash] the object of a flag
@@ -493,31 +494,31 @@ module AEMO
493
494
  end
494
495
  values
495
496
  end
496
-
497
+
497
498
  # @return [Array] CSV of a NEM12 file a given Meter + Data Stream for easy reading
498
499
  def to_csv
499
500
  headers = ['nmi','suffix','units','datetime','value','flags']
500
501
  ([headers]+self.to_a.map{|row| row[3]=row[3].strftime("%Y%m%d%H%M%S%z"); row}).map{|row| row.join(',')}.join("\n")
501
502
  end
502
-
503
+
503
504
  # @param nmi [String] a NMI that is to be checked for validity
504
505
  # @return [Boolean] determines if the NMI is valid
505
506
  def self.valid_nmi?(nmi)
506
507
  (nmi.class == String && nmi.length == 10 && !nmi.match(/^[A-Z1-9][A-Z0-9]{9}$/).nil?)
507
508
  end
508
-
509
+
509
510
  # @param path_to_file [String] the path to a file
510
- # @return [] NEM12 object
511
+ # @return [] NEM12 object
511
512
  def self.parse_nem12_file(path_to_file, strict = false)
512
513
  parse_nem12(File.read(path_to_file),strict)
513
514
  end
514
-
515
+
515
516
  # @param contents [String] the path to a file
516
517
  # @return [Array[AEMO::NEM12]] An array of NEM12 objects
517
518
  def self.parse_nem12(contents, strict=false)
518
519
  file_contents = contents.gsub(/\r/,"\n").gsub(/\n\n/,"\n").split("\n").delete_if{|line| line.empty? }
519
520
  raise ArgumentError, 'First row should be have a RecordIndicator of 100 and be of type Header Record' unless file_contents.first.parse_csv[0] == '100'
520
-
521
+
521
522
  nem12s = []
522
523
  nem12_100 = AEMO::NEM12.parse_nem12_100(file_contents.first,:strict => strict)
523
524
  nem12 = nil
@@ -539,6 +540,6 @@ module AEMO
539
540
  # Return the array of NEM12 groups
540
541
  nem12s
541
542
  end
542
-
543
+
543
544
  end
544
- end
545
+ end
data/lib/aemo/nmi.rb CHANGED
@@ -161,7 +161,7 @@ module AEMO
161
161
  excludes: [
162
162
  ]
163
163
  },
164
- 'TRANSEND' => {
164
+ 'ETSATP' => {
165
165
  title: 'ElectraNet SA',
166
166
  friendly_title: 'ElectraNet SA',
167
167
  state: 'SA',
@@ -398,7 +398,7 @@ module AEMO
398
398
  }
399
399
  # Transmission Node Identifier Codes are loaded from a json file
400
400
  # Obtained from http://www.nemweb.com.au/
401
- #
401
+ #
402
402
  # See /lib/data for further data manipulation required
403
403
  TNI_CODES = JSON.parse(File.read(File.join(File.dirname(__FILE__),'..','data','aemo-tni.json')))
404
404
  # Distribution Loss Factor Codes are loaded from a json file
@@ -406,7 +406,7 @@ module AEMO
406
406
  # Last accessed 2015-02-06
407
407
  # See /lib/data for further data manipulation required
408
408
  DLF_CODES = JSON.parse(File.read(File.join(File.dirname(__FILE__),'..','data','aemo-dlf.json')))
409
-
409
+
410
410
  # [String] National Meter Identifier
411
411
  @nmi = nil
412
412
  @msats_detail = nil
@@ -421,9 +421,9 @@ module AEMO
421
421
  @meters = nil
422
422
  @roles = nil
423
423
  @data_streams = nil
424
-
424
+
425
425
  attr_accessor :nmi, :msats_detail, :tni, :dlf, :customer_classification_code, :customer_threshold_code, :jurisdiction_code, :classification_code, :status, :address, :meters, :roles, :data_streams
426
-
426
+
427
427
  # Initialize a NEM12 file
428
428
  #
429
429
  # @param nmi [String] the National Meter Identifier (NMI)
@@ -433,7 +433,7 @@ module AEMO
433
433
  raise ArgumentError.new("NMI is not a string") unless nmi.is_a?(String)
434
434
  raise ArgumentError.new("NMI is not 10 characters") unless nmi.length == 10
435
435
  raise ArgumentError.new("NMI is not constructed with valid characters") unless AEMO::NMI.valid_nmi?(nmi)
436
-
436
+
437
437
  @nmi = nmi
438
438
  @meters = []
439
439
  @roles = {}
@@ -446,14 +446,14 @@ module AEMO
446
446
  def valid_nmi?
447
447
  AEMO::NMI.valid_nmi?(@nmi)
448
448
  end
449
-
449
+
450
450
  # Find the Network of NMI
451
451
  #
452
452
  # @returns [Hash] The Network information
453
453
  def network
454
454
  AEMO::NMI.network(@nmi)
455
455
  end
456
-
456
+
457
457
  # A function to calculate the checksum value for a given National Meter Identifier
458
458
  #
459
459
  # @param checksum_value [Integer] the checksum value to check against the current National Meter Identifier's checksum value
@@ -474,20 +474,20 @@ module AEMO
474
474
  end
475
475
  value = value.to_s.split(//).map{|i| i.to_i}.reduce(:+)
476
476
  summation += value
477
- end
477
+ end
478
478
  checksum = (10 - (summation % 10)) % 10
479
479
  checksum
480
480
  end
481
-
481
+
482
482
  # Provided MSATS is configured, gets the MSATS data for the NMI
483
483
  #
484
484
  # @return [Hash] MSATS NMI Detail data
485
485
  def raw_msats_nmi_detail
486
486
  raise ArgumentError, 'MSATS has no authentication credentials' unless AEMO::MSATS.can_authenticate?
487
-
487
+
488
488
  AEMO::MSATS.nmi_detail(@nmi)
489
489
  end
490
-
490
+
491
491
  # Provided MSATS is configured, uses the raw MSATS data to augment NMI information
492
492
  #
493
493
  # @return [self] returns self
@@ -573,7 +573,7 @@ module AEMO
573
573
  def meters_by_status(status = 'C')
574
574
  @meters.select{|x| x.status == "#{status}"}
575
575
  end
576
-
576
+
577
577
  # Returns the data_stream OpenStructs for the requested status (A/I)
578
578
  #
579
579
  # @param status [String] the stateus [A|I]
@@ -581,14 +581,14 @@ module AEMO
581
581
  def data_streams_by_status(status = 'A')
582
582
  @data_streams.select{|x| x.status == "#{status}"}
583
583
  end
584
-
584
+
585
585
  # The current daily load
586
586
  #
587
587
  # @return [Integer] the current daily load for the meter
588
588
  def current_daily_load
589
589
  data_streams_by_status().inject(0) { |sum, stream| sum += stream.averaged_daily_load.to_i }
590
590
  end
591
-
591
+
592
592
  # A function to validate the NMI provided
593
593
  #
594
594
  # @param nmi [String] the nmi to be checked
@@ -606,7 +606,7 @@ module AEMO
606
606
  nmi = AEMO::NMI.new(nmi)
607
607
  nmi.valid_checksum?(checksum_value)
608
608
  end
609
-
609
+
610
610
  # Find the Network for a given NMI
611
611
  #
612
612
  # @param nmi [String] NMI
@@ -633,5 +633,5 @@ module AEMO
633
633
  end
634
634
 
635
635
  end
636
-
636
+
637
637
  end
data/lib/aemo/version.rb CHANGED
@@ -22,8 +22,8 @@
22
22
  # @author Joel Courtney <euphemize@gmail.com>
23
23
  module AEMO
24
24
  # aemo version
25
- VERSION = '0.1.14'
25
+ VERSION = '0.1.15'
26
26
 
27
27
  # aemo version split amongst different revisions
28
28
  MAJOR_VERSION, MINOR_VERSION, REVISION = VERSION.split('.').map(&:to_i)
29
- end
29
+ end
metadata CHANGED
@@ -1,14 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aemo
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.14
4
+ version: 0.1.15
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joel Courtney
8
+ - Stuart Auld
8
9
  autorequire:
9
10
  bindir: bin
10
11
  cert_chain: []
11
- date: 2015-03-23 00:00:00.000000000 Z
12
+ date: 2015-08-27 00:00:00.000000000 Z
12
13
  dependencies:
13
14
  - !ruby/object:Gem::Dependency
14
15
  name: json
@@ -24,6 +25,40 @@ dependencies:
24
25
  - - "~>"
25
26
  - !ruby/object:Gem::Version
26
27
  version: '1.8'
28
+ - !ruby/object:Gem::Dependency
29
+ name: nokogiri
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - "~>"
33
+ - !ruby/object:Gem::Version
34
+ version: '1.6'
35
+ - - ">="
36
+ - !ruby/object:Gem::Version
37
+ version: 1.6.6
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ requirements:
42
+ - - "~>"
43
+ - !ruby/object:Gem::Version
44
+ version: '1.6'
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: 1.6.6
48
+ - !ruby/object:Gem::Dependency
49
+ name: zip
50
+ requirement: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '2.0'
55
+ type: :runtime
56
+ prerelease: false
57
+ version_requirements: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '2.0'
27
62
  - !ruby/object:Gem::Dependency
28
63
  name: multi_xml
29
64
  requirement: !ruby/object:Gem::Requirement
@@ -68,6 +103,7 @@ description: Gem providing functionality for the Australian Energy Market Operat
68
103
  data
69
104
  email:
70
105
  - jcourtney@cozero.com.au
106
+ - sauld@cozero.com.au
71
107
  executables: []
72
108
  extensions: []
73
109
  extra_rdoc_files: []
@@ -223,7 +259,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
223
259
  version: '0'
224
260
  requirements: []
225
261
  rubyforge_project:
226
- rubygems_version: 2.2.2
262
+ rubygems_version: 2.4.6
227
263
  signing_key:
228
264
  specification_version: 4
229
265
  summary: AEMO Gem
@@ -337,4 +373,3 @@ test_files:
337
373
  - spec/fixtures/nmi_checksum.json
338
374
  - spec/spec.opts
339
375
  - spec/spec_helper.rb
340
- has_rdoc: