aemo 0.1.14 → 0.1.15

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 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: