aemo 0.1.39 → 0.1.40

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: 393bc9a0f07713e90556d7704bb2d129bc398e1d
4
- data.tar.gz: 9d370f741128cc703d0f4f492508a6455203c5e3
3
+ metadata.gz: 99c92027fe76a3d8367716e2274157b9239c48ee
4
+ data.tar.gz: 70d04cf7ed134fc1ac3aab96d8727e043c19104b
5
5
  SHA512:
6
- metadata.gz: 40d6fc601b3f55f8c02cc4c9753e29e89e366ce4c9fd951bfd5708c1843286f064ffd5cbe24bec58bbdd8d95a4d006a2662943571e6c89501e9a9b0d8e6cc99b
7
- data.tar.gz: 6e716d57f1ab10b2af33e7f70df066cba1142faa5d518cd6b27bb3280d03b3913b370532a1440dfc327f0c16b513accf1648f5d55af9c0983c626b7505a7e5c4
6
+ metadata.gz: 0ed1e45c8450de68f0adccf41f87ccbe0bb6cf44d87c417826f75b2738ecc8c13480eb7e087b5f5b66dfc9f73bbb83d887ed88008a773b76f3c9effd62dd8cd2
7
+ data.tar.gz: 8aadfb1e0b590c4527b01fa21cba54f1b651b78e613b834b86fd21716298612647719a23c6010b0e5abc21bdfacb1ea97becded6de357b058f715dba5c2679fb
data/lib/aemo.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'active_support/all'
2
4
  require 'httparty'
3
5
  require 'csv'
@@ -6,9 +8,11 @@ require 'aemo/region.rb'
6
8
  require 'aemo/market.rb'
7
9
  require 'aemo/market/interval.rb'
8
10
  require 'aemo/market/node.rb'
11
+ require 'aemo/meter.rb'
9
12
  require 'aemo/nem12.rb'
10
13
  require 'aemo/nmi.rb'
11
14
  require 'aemo/msats.rb'
15
+ require 'aemo/register.rb'
12
16
  require 'aemo/version.rb'
13
17
 
14
18
  # AEMO Module to encapsulate all AEMO classes
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module AEMO
2
4
  class Region
3
5
  DISPATCH_TYPE = ['Generator', 'Load Norm Off', 'Network Service Provider'].freeze
data/lib/aemo/market.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module AEMO
2
4
  # AEMO::Market
3
5
  #
@@ -13,7 +15,7 @@ module AEMO
13
15
  # Return the current dispatch dataset for a region
14
16
  #
15
17
  # @param [String, AEMO::Region] region AEMO::Region
16
- # @return [Array<AEMO::Market::Interval>] an array of AEMO::Market::Intervals
18
+ # @return [Array<AEMO::Market::Interval>] the current dispatch data
17
19
  def current_dispatch(region)
18
20
  region = AEMO::Region.new(region) if region.is_a?(String)
19
21
 
@@ -25,7 +27,7 @@ module AEMO
25
27
  # Description of method
26
28
  #
27
29
  # @param [String, AEMO::Region] region AEMO::Region
28
- # @return [Array<AEMO::Market::Interval>] an array of AEMO::Market::Intervals
30
+ # @return [Array<AEMO::Market::Interval>] the current trading data
29
31
  def current_trading(region)
30
32
  region = AEMO::Region.new(region) if region.is_a?(String)
31
33
 
@@ -44,16 +46,19 @@ module AEMO
44
46
  region = AEMO::Region.new(region) if region.is_a?(String)
45
47
 
46
48
  required_data = []
47
- (start..finish).map { |d| { year: d.year, month: d.month } }.uniq.each do |period|
48
- required_data += historic_trading(region, period[:year], period[:month])
49
+ (start..finish).map { |d| { year: d.year, month: d.month } }
50
+ .uniq.each do |period|
51
+ required_data += historic_trading(region, period[:year],
52
+ period[:month])
49
53
  end
50
54
 
51
- required_data.select { |values| values.datetime >= start && values.datetime <= finish }
55
+ required_data.select do |values|
56
+ values.datetime >= start && values.datetime <= finish
57
+ end
52
58
  end
53
59
 
54
60
  # Return an array of historic trading values for a Year, Month and Region
55
- # As per the historical data at
56
- # http://www.aemo.com.au/Electricity/Data/Price-and-Demand/Aggregated-Price-and-Demand-Data-Files/Aggregated-Price-and-Demand-2011-to-2016
61
+ # As per the historical data from AEMO
57
62
  #
58
63
  # @param [String, AEMO::Region] region AEMO::Region
59
64
  # @param [Integer] year The year for the report from AEMO
@@ -62,11 +67,12 @@ module AEMO
62
67
  def historic_trading(region, year, month)
63
68
  region = AEMO::Region.new(region) if region.is_a?(String)
64
69
 
65
- month = sprintf('%02d', month)
70
+ month = Kernel.format('%02d', month)
71
+ url = 'https://aemo.com.au/aemo/data/nem/priceanddemand/' \
72
+ "PRICE_AND_DEMAND_#{year}#{month}_#{region}1.csv"
66
73
 
67
- response = HTTParty.get("http://aemo.com.au/aemo/data/nem/priceanddemand/PRICE_AND_DEMAND_#{year}#{month}_#{region}1.csv")
68
- values = parse_response(response)
69
- values
74
+ response = HTTParty.get(url)
75
+ parse_response(response)
70
76
  end
71
77
 
72
78
  protected
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module AEMO
2
4
  module Market
3
5
  # AEMO::Market::Interval
@@ -14,7 +16,7 @@ module AEMO
14
16
  attr_accessor :datetime, :region, :total_demand, :rrp, :period_type
15
17
 
16
18
  # Create a new instance of an Interval
17
- #
19
+ #
18
20
  # @param [Time] datetime
19
21
  # @param [Hash] options Hash of optional data values
20
22
  # @return [AEMO::Market::Interval]
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module AEMO
2
4
  module Market
3
5
  # AEMO::Market::Interval
@@ -6,7 +8,7 @@ module AEMO
6
8
  # @abstract
7
9
  # @since 0.1.0
8
10
  class Node
9
- IDENTIFIERS = %w(NSW QLD SA TAS VIC)
11
+ IDENTIFIERS = %w[NSW QLD SA TAS VIC].freeze
10
12
 
11
13
  attr_accessor :identifier
12
14
 
@@ -31,7 +33,7 @@ module AEMO
31
33
  #
32
34
  # @return [Array<AEMO::Market::Interval>]
33
35
  def current_trading
34
- if @current_trading.empty? || @current_trading.reject { |i| i.period_type != 'TRADE' }.last.datetime != (Time.now - Time.now.to_i % 300)
36
+ if @current_trading.empty? || @current_trading.select { |i| i.period_type == 'TRADE' }.last.datetime != (Time.now - Time.now.to_i % 300)
35
37
  @current_trading = AEMO::Market.current_trading(@identifier)
36
38
  end
37
39
  @current_trading
data/lib/aemo/meter.rb ADDED
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AEMO
4
+ # AEMO::Meter represents a meter under a NMI
5
+ class Meter
6
+ attr_accessor :installation_type_code, :next_scheduled_read_date,
7
+ :read_type_code, :registers, :serial_number, :status
8
+
9
+ # Initialize a meter
10
+ #
11
+ # @param [Hash] opts = {} the parameters to set
12
+ # @return [AEMO::Meter] an instance of an AEMO::Meter
13
+ def initialize(opts = {})
14
+ @installation_type_code = opts[:installation_type_code]
15
+ @next_scheduled_read_date = opts[:next_scheduled_read_date]
16
+ @read_type_code = opts[:read_type_code]
17
+ @registers = opts[:registers] || []
18
+ @serial_number = opts[:serial_number]
19
+ @status = opts[:status]
20
+ end
21
+
22
+ # Initialize a new meter from an MSATS hash
23
+ #
24
+ # @param [Hash] meter the MSATS hash
25
+ # @return [AEMO::Meter] description of returned object
26
+ def self.from_hash(meter)
27
+ AEMO::Meter.new(
28
+ installation_type_code: meter['InstallationTypeCode'],
29
+ next_scheduled_read_date: meter['NextScheduledReadDate'],
30
+ read_type_code: meter['ReadTypeCode'],
31
+ registers: [],
32
+ serial_number: meter['SerialNumber'],
33
+ status: meter['Status']
34
+ )
35
+ end
36
+ end
37
+ end
data/lib/aemo/msats.rb CHANGED
@@ -1,8 +1,9 @@
1
- require 'httparty'
1
+ # frozen_string_literal: true
2
+
2
3
  require 'aemo'
3
- # require 'zip'
4
- require 'nokogiri'
5
4
  require 'digest/sha1'
5
+ require 'httparty'
6
+ require 'nokogiri'
6
7
 
7
8
  module AEMO
8
9
  # AEMO::MSATS
@@ -93,7 +94,7 @@ module AEMO
93
94
  # @param [Integer] delivery_point_identifier Delivery Point Identifier
94
95
  # @return [Hash] The response
95
96
  def nmi_discovery_by_delivery_point_identifier(jurisdiction_code, delivery_point_identifier, options = {})
96
- raise ArgumentError, 'jurisdiction_code is not valid' unless %w(ACT NEM NSW QLD SA VIC TAS).include?(jurisdiction_code)
97
+ raise ArgumentError, 'jurisdiction_code is not valid' unless %w[ACT NEM NSW QLD SA VIC TAS].include?(jurisdiction_code)
97
98
  raise ArgumentError, 'delivery_point_identifier is not valid' unless delivery_point_identifier.respond_to?('to_i')
98
99
  raise ArgumentError, 'delivery_point_identifier is not valid' if delivery_point_identifier.to_i < 10_000_000 || delivery_point_identifier.to_i > 99_999_999
99
100
 
@@ -117,7 +118,7 @@ module AEMO
117
118
  # @param [Integer] meter_serial_number The meter's serial number
118
119
  # @return [Hash] The response
119
120
  def nmi_discovery_by_meter_serial_number(jurisdiction_code, meter_serial_number, options = {})
120
- raise ArgumentError, 'jurisdiction_code is not valid' unless %w(ACT NEM NSW QLD SA VIC TAS).include?(jurisdiction_code)
121
+ raise ArgumentError, 'jurisdiction_code is not valid' unless %w[ACT NEM NSW QLD SA VIC TAS].include?(jurisdiction_code)
121
122
 
122
123
  query = {
123
124
  transactionId: transaction_id,
@@ -139,7 +140,7 @@ module AEMO
139
140
  # @param [Integer] meter_serial_number The meter's serial number
140
141
  # @return [Hash] The response
141
142
  def nmi_discovery_by_address(jurisdiction_code, options = {})
142
- raise ArgumentError, 'jurisdiction_code is not valid' unless %w(ACT NEM NSW QLD SA VIC TAS).include?(jurisdiction_code)
143
+ raise ArgumentError, 'jurisdiction_code is not valid' unless %w[ACT NEM NSW QLD SA VIC TAS].include?(jurisdiction_code)
143
144
 
144
145
  options[:building_or_property_name] ||= nil
145
146
  options[:location_descriptor] ||= nil
data/lib/aemo/nem12.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'csv'
2
4
  require 'time'
3
5
 
@@ -92,36 +94,36 @@ module AEMO
92
94
  }.freeze
93
95
 
94
96
  METHOD_FLAGS = {
95
- 11 => { type: %w(SUB), installation_type: [1, 2, 3, 4], short_descriptor: 'Check', description: '' },
96
- 12 => { type: %w(SUB), installation_type: [1, 2, 3, 4], short_descriptor: 'Calculated', description: '' },
97
- 13 => { type: %w(SUB), installation_type: [1, 2, 3, 4], short_descriptor: 'SCADA', description: '' },
98
- 14 => { type: %w(SUB), installation_type: [1, 2, 3, 4], short_descriptor: 'Like Day', description: '' },
99
- 15 => { type: %w(SUB), installation_type: [1, 2, 3, 4], short_descriptor: 'Average Like Day', description: '' },
100
- 16 => { type: %w(SUB), installation_type: [1, 2, 3, 4], short_descriptor: 'Agreed', description: '' },
101
- 17 => { type: %w(SUB), installation_type: [1, 2, 3, 4], short_descriptor: 'Linear', description: '' },
102
- 18 => { type: %w(SUB), installation_type: [1, 2, 3, 4], short_descriptor: 'Alternate', description: '' },
103
- 19 => { type: %w(SUB), installation_type: [1, 2, 3, 4], short_descriptor: 'Zero', description: '' },
104
- 51 => { type: %w(EST SUB), installation_type: 5, short_descriptor: 'Previous Year', description: '' },
105
- 52 => { type: %w(EST SUB), installation_type: 5, short_descriptor: 'Previous Read', description: '' },
106
- 53 => { type: %w(SUB), installation_type: 5, short_descriptor: 'Revision', description: '' },
107
- 54 => { type: %w(SUB), installation_type: 5, short_descriptor: 'Linear', description: '' },
108
- 55 => { type: %w(SUB), installation_type: 5, short_descriptor: 'Agreed', description: '' },
109
- 56 => { type: %w(EST SUB), installation_type: 5, short_descriptor: 'Prior to First Read - Agreed', description: '' },
110
- 57 => { type: %w(EST SUB), installation_type: 5, short_descriptor: 'Customer Class', description: '' },
111
- 58 => { type: %w(EST SUB), installation_type: 5, short_descriptor: 'Zero', description: '' },
112
- 61 => { type: %w(EST SUB), installation_type: 6, short_descriptor: 'Previous Year', description: '' },
113
- 62 => { type: %w(EST SUB), installation_type: 6, short_descriptor: 'Previous Read', description: '' },
114
- 63 => { type: %w(EST SUB), installation_type: 6, short_descriptor: 'Customer Class', description: '' },
115
- 64 => { type: %w(SUB), installation_type: 6, short_descriptor: 'Agreed', description: '' },
116
- 65 => { type: %w(EST), installation_type: 6, short_descriptor: 'ADL', description: '' },
117
- 66 => { type: %w(SUB), installation_type: 6, short_descriptor: 'Revision', description: '' },
118
- 67 => { type: %w(SUB), installation_type: 6, short_descriptor: 'Customer Read', description: '' },
119
- 68 => { type: %w(EST SUB), installation_type: 6, short_descriptor: 'Zero', description: '' },
120
- 71 => { type: %w(SUB), installation_type: 7, short_descriptor: 'Recalculation', description: '' },
121
- 72 => { type: %w(SUB), installation_type: 7, short_descriptor: 'Revised Table', description: '' },
122
- 73 => { type: %w(SUB), installation_type: 7, short_descriptor: 'Revised Algorithm', description: '' },
123
- 74 => { type: %w(SUB), installation_type: 7, short_descriptor: 'Agreed', description: '' },
124
- 75 => { type: %w(EST), installation_type: 7, short_descriptor: 'Existing Table', description: '' }
97
+ 11 => { type: %w[SUB], installation_type: [1, 2, 3, 4], short_descriptor: 'Check', description: '' },
98
+ 12 => { type: %w[SUB], installation_type: [1, 2, 3, 4], short_descriptor: 'Calculated', description: '' },
99
+ 13 => { type: %w[SUB], installation_type: [1, 2, 3, 4], short_descriptor: 'SCADA', description: '' },
100
+ 14 => { type: %w[SUB], installation_type: [1, 2, 3, 4], short_descriptor: 'Like Day', description: '' },
101
+ 15 => { type: %w[SUB], installation_type: [1, 2, 3, 4], short_descriptor: 'Average Like Day', description: '' },
102
+ 16 => { type: %w[SUB], installation_type: [1, 2, 3, 4], short_descriptor: 'Agreed', description: '' },
103
+ 17 => { type: %w[SUB], installation_type: [1, 2, 3, 4], short_descriptor: 'Linear', description: '' },
104
+ 18 => { type: %w[SUB], installation_type: [1, 2, 3, 4], short_descriptor: 'Alternate', description: '' },
105
+ 19 => { type: %w[SUB], installation_type: [1, 2, 3, 4], short_descriptor: 'Zero', description: '' },
106
+ 51 => { type: %w[EST SUB], installation_type: 5, short_descriptor: 'Previous Year', description: '' },
107
+ 52 => { type: %w[EST SUB], installation_type: 5, short_descriptor: 'Previous Read', description: '' },
108
+ 53 => { type: %w[SUB], installation_type: 5, short_descriptor: 'Revision', description: '' },
109
+ 54 => { type: %w[SUB], installation_type: 5, short_descriptor: 'Linear', description: '' },
110
+ 55 => { type: %w[SUB], installation_type: 5, short_descriptor: 'Agreed', description: '' },
111
+ 56 => { type: %w[EST SUB], installation_type: 5, short_descriptor: 'Prior to First Read - Agreed', description: '' },
112
+ 57 => { type: %w[EST SUB], installation_type: 5, short_descriptor: 'Customer Class', description: '' },
113
+ 58 => { type: %w[EST SUB], installation_type: 5, short_descriptor: 'Zero', description: '' },
114
+ 61 => { type: %w[EST SUB], installation_type: 6, short_descriptor: 'Previous Year', description: '' },
115
+ 62 => { type: %w[EST SUB], installation_type: 6, short_descriptor: 'Previous Read', description: '' },
116
+ 63 => { type: %w[EST SUB], installation_type: 6, short_descriptor: 'Customer Class', description: '' },
117
+ 64 => { type: %w[SUB], installation_type: 6, short_descriptor: 'Agreed', description: '' },
118
+ 65 => { type: %w[EST], installation_type: 6, short_descriptor: 'ADL', description: '' },
119
+ 66 => { type: %w[SUB], installation_type: 6, short_descriptor: 'Revision', description: '' },
120
+ 67 => { type: %w[SUB], installation_type: 6, short_descriptor: 'Customer Read', description: '' },
121
+ 68 => { type: %w[EST SUB], installation_type: 6, short_descriptor: 'Zero', description: '' },
122
+ 71 => { type: %w[SUB], installation_type: 7, short_descriptor: 'Recalculation', description: '' },
123
+ 72 => { type: %w[SUB], installation_type: 7, short_descriptor: 'Revised Table', description: '' },
124
+ 73 => { type: %w[SUB], installation_type: 7, short_descriptor: 'Revised Algorithm', description: '' },
125
+ 74 => { type: %w[SUB], installation_type: 7, short_descriptor: 'Agreed', description: '' },
126
+ 75 => { type: %w[EST], installation_type: 7, short_descriptor: 'Existing Table', description: '' }
125
127
  }.freeze
126
128
 
127
129
  REASON_CODES = {
@@ -332,7 +334,7 @@ module AEMO
332
334
  end
333
335
  raise ArgumentError, 'UOM is not valid' if csv[7].upcase.match(/[A-Z0-9]{2}/).nil?
334
336
  raise ArgumentError, 'UOM is not valid' unless UOM.keys.map(&:upcase).include?(csv[7].upcase)
335
- raise ArgumentError, 'IntervalLength is not valid' unless %w(1 5 10 15 30).include?(csv[8])
337
+ raise ArgumentError, 'IntervalLength is not valid' unless %w[1 5 10 15 30].include?(csv[8])
336
338
  # raise ArgumentError, 'NextScheduledReadDate is not valid' if csv[9].match(/\d{8}/).nil? || csv[9] != Time.parse('#{csv[9]}').strftime('%Y%m%d')
337
339
 
338
340
  @nmi = AEMO::NMI.new(csv[1])
@@ -369,14 +371,14 @@ module AEMO
369
371
  raise ArgumentError, 'QualityMethod is not valid' unless csv[intervals_offset + 0].class == String
370
372
  raise ArgumentError, 'QualityMethod does not have valid length' unless [1, 3].include?(csv[intervals_offset + 0].length)
371
373
  raise ArgumentError, 'QualityMethod does not have valid QualityFlag' unless QUALITY_FLAGS.keys.include?(csv[intervals_offset + 0][0])
372
- unless %w(A N V).include?(csv[intervals_offset + 0][0])
374
+ unless %w[A N V].include?(csv[intervals_offset + 0][0])
373
375
  raise ArgumentError, 'QualityMethod does not have valid length' unless csv[intervals_offset + 0].length == 3
374
376
  raise ArgumentError, 'QualityMethod does not have valid MethodFlag' unless METHOD_FLAGS.keys.include?(csv[intervals_offset + 0][1..2].to_i)
375
377
  end
376
- unless %w(A N E).include?(csv[intervals_offset + 0][0])
378
+ unless %w[A N E].include?(csv[intervals_offset + 0][0])
377
379
  raise ArgumentError, 'ReasonCode is not valid' unless REASON_CODES.keys.include?(csv[intervals_offset + 1].to_i)
378
380
  end
379
- if !csv[intervals_offset + 1].nil? && csv[intervals_offset + 1].to_i == 0
381
+ if !csv[intervals_offset + 1].nil? && csv[intervals_offset + 1].to_i.zero?
380
382
  raise ArgumentError, 'ReasonDescription is not valid' unless csv[intervals_offset + 2].class == String && !csv[intervals_offset + 2].empty?
381
383
  end
382
384
  if options[:strict]
@@ -429,7 +431,7 @@ module AEMO
429
431
  interval_events = []
430
432
 
431
433
  # Only need to update flags for EFSV
432
- unless %w(A N).include?csv[3]
434
+ unless %w[A N].include? csv[3]
433
435
  number_of_intervals = 1440 / @data_details.last[:interval_length]
434
436
  interval_start_point = @interval_data.length - number_of_intervals
435
437
 
@@ -460,13 +462,11 @@ module AEMO
460
462
 
461
463
  # @param [String] line A single line in string format
462
464
  # @return [Hash] the line parsed into a hash of information
463
- def parse_nem12_500(_line, _options = {})
464
- end
465
+ def parse_nem12_500(_line, _options = {}); end
465
466
 
466
467
  # @param [String] line A single line in string format
467
468
  # @return [Hash] the line parsed into a hash of information
468
- def parse_nem12_900(_line, _options = {})
469
- end
469
+ def parse_nem12_900(_line, _options = {}); end
470
470
 
471
471
  # Turns the flag to a string
472
472
  #
@@ -498,7 +498,7 @@ module AEMO
498
498
 
499
499
  # @return [Array] CSV of a NEM12 file a given Meter + Data Stream for easy reading
500
500
  def to_csv
501
- headers = %w(nmi suffix units datetime value flags)
501
+ headers = %w[nmi suffix units datetime value flags]
502
502
  ([headers] + to_a.map do |row|
503
503
  row[3] = row[3].strftime('%Y%m%d%H%M%S%z')
504
504
  row
data/lib/aemo/nem13.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module AEMO
2
4
  class NEM13
3
5
  end
data/lib/aemo/nmi.rb CHANGED
@@ -1,412 +1,328 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'csv'
2
4
  require 'json'
3
5
  require 'time'
4
6
  require 'ostruct'
5
7
  module AEMO
6
- # AEMO::NMI acts as an object to simplify access to data and information about a NMI and provide verification of the NMI value
8
+ # AEMO::NMI acts as an object to simplify access to data and information
9
+ # about a NMI and provide verification of the NMI value
7
10
  class NMI
8
11
  # Operational Regions for the NMI
9
- REGIONS = {
10
- 'ACT' => 'Australian Capital Territory',
11
- 'NSW' => 'New South Wales',
12
- 'QLD' => 'Queensland',
13
- 'SA' => 'South Australia',
14
- 'TAS' => 'Tasmania',
15
- 'VIC' => 'Victoria',
16
- 'WA' => 'Western Australia',
17
- 'NT' => 'Northern Territory'
18
- }.freeze
12
+ REGIONS = { 'ACT' => 'Australian Capital Territory',
13
+ 'NSW' => 'New South Wales',
14
+ 'QLD' => 'Queensland',
15
+ 'SA' => 'South Australia',
16
+ 'TAS' => 'Tasmania',
17
+ 'VIC' => 'Victoria',
18
+ 'WA' => 'Western Australia',
19
+ 'NT' => 'Northern Territory' }.freeze
19
20
 
20
- # NMI_ALLOCATIONS as per AEMO Documentation at http://aemo.com.au/Electricity/Policies-and-Procedures/Retail-and-Metering/~/media/Files/Other/Retail% 20and% 20Metering/NMI_Allocation_List_v7_June_2012.ashx
21
- # Last accessed 2016-05-15
21
+ # NMI_ALLOCATIONS as per AEMO Documentation at
22
+ # https://www.aemo.com.au/-/media/Files/Electricity/NEM/Retail_and_Metering/
23
+ # Metering-Procedures/NMI-Allocation-List.pdf
24
+ # Last accessed 2017-08-01
22
25
  NMI_ALLOCATIONS = {
23
26
  'ACTEWP' => {
24
27
  title: 'Actew Distribution Ltd and Jemena Networks (ACT) Pty Ltd',
25
28
  friendly_title: 'ACTEWAgl',
26
29
  state: AEMO::Region.new('ACT'),
27
30
  type: 'electricity',
28
- includes: [
29
- /^(NGGG[A-HJ-NP-VX-Z\d][A-HJ-NP-Z\d]{5})$/,
30
- /^(7001\d{6})$/
31
- ],
32
- excludes: [
33
- ]
31
+ includes: [/^(NGGG[A-HJ-NP-VX-Z\d][A-HJ-NP-Z\d]{5})$/,
32
+ /^(7001\d{6})$/],
33
+ excludes: []
34
34
  },
35
35
  'CNRGYP' => {
36
36
  title: 'Essential Energy',
37
37
  friendly_title: 'Essential Energy',
38
38
  state: AEMO::Region.new('NSW'),
39
39
  type: 'electricity',
40
- includes: [
41
- /^(NAAA[A-HJ-NP-VX-Z\d][A-HJ-NP-Z\d]{5})$/,
42
- /^(NBBB[A-HJ-NP-VX-Z\d][A-HJ-NP-Z\d]{5})$/,
43
- /^(NDDD[A-HJ-NP-VX-Z\d][A-HJ-NP-Z\d]{5})$/,
44
- /^(NFFF[A-HJ-NP-VX-Z\d][A-HJ-NP-Z\d]{5})$/,
45
- /^(4001\d{6})$/,
46
- /^(4508\d{6})$/,
47
- /^(4204\d{6})$/,
48
- /^(4407\d{6})$/
49
- ],
50
- excludes: [
51
- ]
40
+ includes: [/^(NAAA[A-HJ-NP-VX-Z\d][A-HJ-NP-Z\d]{5})$/,
41
+ /^(NBBB[A-HJ-NP-VX-Z\d][A-HJ-NP-Z\d]{5})$/,
42
+ /^(NDDD[A-HJ-NP-VX-Z\d][A-HJ-NP-Z\d]{5})$/,
43
+ /^(NFFF[A-HJ-NP-VX-Z\d][A-HJ-NP-Z\d]{5})$/,
44
+ /^(4001\d{6})$/,
45
+ /^(4508\d{6})$/,
46
+ /^(4204\d{6})$/,
47
+ /^(4407\d{6})$/],
48
+ excludes: []
52
49
  },
53
50
  'ENERGYAP' => {
54
51
  title: 'Ausgrid',
55
52
  friendly_title: 'Ausgrid',
56
53
  state: AEMO::Region.new('NSW'),
57
54
  type: 'electricity',
58
- includes: [
59
- /^(NCCC[A-HJ-NP-VX-Z\d][A-HJ-NP-Z\d]{5})$/,
60
- /^(410[234]\d{6})$/
61
- ],
62
- excludes: [
63
- ]
55
+ includes: [/^(NCCC[A-HJ-NP-VX-Z\d][A-HJ-NP-Z\d]{5})$/,
56
+ /^(410[234]\d{6})$/],
57
+ excludes: []
64
58
  },
65
59
  'INTEGP' => {
66
60
  title: 'Endeavour Energy',
67
61
  friendly_title: 'Endeavour Energy',
68
62
  state: AEMO::Region.new('NSW'),
69
63
  type: 'electricity',
70
- includes: [
71
- /^(NEEE[A-HJ-NP-VX-Z\d][A-HJ-NP-Z\d]{5})$/,
72
- /^(431\d{7})$/
73
- ],
74
- excludes: [
75
- ]
64
+ includes: [/^(NEEE[A-HJ-NP-VX-Z\d][A-HJ-NP-Z\d]{5})$/,
65
+ /^(431\d{7})$/],
66
+ excludes: []
76
67
  },
77
68
  'TRANSGP' => {
78
69
  title: 'TransGrid',
79
70
  friendly_title: 'TransGrid',
80
71
  state: AEMO::Region.new('NSW'),
81
72
  type: 'electricity',
82
- includes: [
83
- /^(NTTT[A-HJ-NP-VX-Z\d][A-HJ-NP-Z\d]{5})$/,
84
- /^(460810[0-8]\d{3})$/
85
- ],
86
- excludes: [
87
- ]
73
+ includes: [/^(NTTT[A-HJ-NP-VX-Z\d][A-HJ-NP-Z\d]{5})$/,
74
+ /^(460810[0-8]\d{3})$/],
75
+ excludes: []
88
76
  },
89
77
  'SNOWY' => {
90
78
  title: 'Snowy Hydro Ltd',
91
79
  friendly_title: 'Snowy Hydro',
92
80
  state: AEMO::Region.new('NSW'),
93
81
  type: 'electricity',
94
- includes: [
95
- /^(4708109\d{3})$/
96
- ],
97
- excludes: [
98
- ]
82
+ includes: [/^(4708109\d{3})$/],
83
+ excludes: []
99
84
  },
100
85
  'NT_RESERVED' => {
101
86
  title: 'Northern Territory Reserved Block',
102
87
  friendly_title: 'Northern Territory Reserved Block',
103
88
  state: AEMO::Region.new('NT'),
104
89
  type: 'electricity',
105
- includes: [
106
- /^(250\d{7})$/
107
- ],
108
- excludes: [
109
- ]
90
+ includes: [/^(250\d{7})$/],
91
+ excludes: []
110
92
  },
111
93
  'ERGONETP' => {
112
94
  title: 'Ergon Energy Corporation',
113
95
  friendly_title: 'Ergon Energy',
114
96
  state: AEMO::Region.new('QLD'),
115
97
  type: 'electricity',
116
- includes: [
117
- /^(QAAA[A-HJ-NP-VX-Z\d][A-HJ-NP-Z\d]{5})$/,
118
- /^(QCCC[A-HJ-NP-VX-Z\d][A-HJ-NP-Z\d]{5})$/,
119
- /^(QDDD[A-HJ-NP-VX-Z\d][A-HJ-NP-Z\d]{5})$/,
120
- /^(QEEE[A-HJ-NP-VX-Z\d][A-HJ-NP-Z\d]{5})$/,
121
- /^(QFFF[A-HJ-NP-VX-Z\d][A-HJ-NP-Z\d]{5})$/,
122
- /^(QGGG[A-HJ-NP-VX-Z\d][A-HJ-NP-Z\d]{5})$/,
123
- /^(30\d{8})$/
124
- ],
125
- excludes: [
126
- ]
98
+ includes: [/^(QAAA[A-HJ-NP-VX-Z\d][A-HJ-NP-Z\d]{5})$/,
99
+ /^(QCCC[A-HJ-NP-VX-Z\d][A-HJ-NP-Z\d]{5})$/,
100
+ /^(QDDD[A-HJ-NP-VX-Z\d][A-HJ-NP-Z\d]{5})$/,
101
+ /^(QEEE[A-HJ-NP-VX-Z\d][A-HJ-NP-Z\d]{5})$/,
102
+ /^(QFFF[A-HJ-NP-VX-Z\d][A-HJ-NP-Z\d]{5})$/,
103
+ /^(QGGG[A-HJ-NP-VX-Z\d][A-HJ-NP-Z\d]{5})$/,
104
+ /^(30\d{8})$/],
105
+ excludes: []
127
106
  },
128
107
  'ENERGEXP' => {
129
108
  title: 'ENERGEX Limited',
130
109
  friendly_title: 'Energex',
131
110
  state: AEMO::Region.new('QLD'),
132
111
  type: 'electricity',
133
- includes: [
134
- /^(QB\d{2}[A-HJ-NP-VX-Z\d][A-HJ-NP-Z\d]{5})$/,
135
- /^(31\d{8})$/
136
- ],
137
- excludes: [
138
- ]
112
+ includes: [/^(QB\d{2}[A-HJ-NP-VX-Z\d][A-HJ-NP-Z\d]{5})$/,
113
+ /^(31\d{8})$/],
114
+ excludes: []
139
115
  },
140
116
  'PLINKP' => {
141
117
  title: 'Qld Electricity Transmission Corp (Powerlink)',
142
118
  friendly_title: 'Powerlink',
143
119
  state: AEMO::Region.new('QLD'),
144
120
  type: 'electricity',
145
- includes: [
146
- /^(Q[A-HJ-NP-Z\d]{3}W[A-HJ-NP-Z\d]{5})$/,
147
- /^(320200\d{4})$/
148
- ],
149
- excludes: [
150
- ]
121
+ includes: [/^(Q[A-HJ-NP-Z\d]{3}W[A-HJ-NP-Z\d]{5})$/,
122
+ /^(320200\d{4})$/],
123
+ excludes: []
151
124
  },
152
125
  'UMPLP' => {
153
126
  title: 'SA Power Networks',
154
127
  friendly_title: 'SA Power Networks',
155
128
  state: AEMO::Region.new('SA'),
156
129
  type: 'electricity',
157
- includes: [
158
- /^(SAAA[A-HJ-NP-VX-Z\d][A-HJ-NP-Z\d]{5})$/,
159
- /^(SASMPL[\d]{4})$/,
160
- /^(200[12]\d{6})$/
161
- ],
162
- excludes: [
163
- ]
130
+ includes: [/^(SAAA[A-HJ-NP-VX-Z\d][A-HJ-NP-Z\d]{5})$/,
131
+ /^(SASMPL[\d]{4})$/,
132
+ /^(200[12]\d{6})$/],
133
+ excludes: []
164
134
  },
165
135
  'ETSATP' => {
166
136
  title: 'ElectraNet SA',
167
137
  friendly_title: 'ElectraNet SA',
168
138
  state: AEMO::Region.new('SA'),
169
139
  type: 'electricity',
170
- includes: [
171
- /^(S[A-HJ-NP-Z\d]{3}W[A-HJ-NP-Z\d]{5})$/,
172
- /^(210200\d{4})$/
173
- ],
174
- excludes: [
175
- ]
140
+ includes: [/^(S[A-HJ-NP-Z\d]{3}W[A-HJ-NP-Z\d]{5})$/,
141
+ /^(210200\d{4})$/],
142
+ excludes: []
176
143
  },
177
144
  'AURORAP' => {
178
145
  title: 'TasNetworks',
179
146
  friendly_title: 'TasNetworks',
180
147
  state: AEMO::Region.new('TAS'),
181
148
  type: 'electricity',
182
- includes: [
183
- /^(T000000(([0-4]\d{3})|(500[01])))$/,
184
- /^(8000\d{6})$/,
185
- /^(8590[23]\d{5})$/
186
- ],
187
- excludes: [
188
- ]
149
+ includes: [/^(T000000(([0-4]\d{3})|(500[01])))$/,
150
+ /^(8000\d{6})$/,
151
+ /^(8590[23]\d{5})$/],
152
+ excludes: []
189
153
  },
190
154
  'TRANSEND' => {
191
155
  title: 'TasNetworks',
192
156
  friendly_title: 'TasNetworks',
193
157
  state: AEMO::Region.new('TAS'),
194
158
  type: 'electricity',
195
- includes: [
196
- /^(T[A-HJ-NP-Z\d]{3}W[A-HJ-NP-Z\d]{5})$/
197
- ],
198
- excludes: [
199
- ]
159
+ includes: [/^(T[A-HJ-NP-Z\d]{3}W[A-HJ-NP-Z\d]{5})$/],
160
+ excludes: []
200
161
  },
201
162
  'CITIPP' => {
202
163
  title: 'CitiPower',
203
164
  friendly_title: 'CitiPower',
204
165
  state: AEMO::Region.new('VIC'),
205
166
  type: 'electricity',
206
- includes: [
207
- /^(VAAA[A-HJ-NP-VX-Z\d][A-HJ-NP-Z\d]{5})$/,
208
- /^(610[23]\d{6})$/
209
- ],
210
- excludes: [
211
- ]
167
+ includes: [/^(VAAA[A-HJ-NP-VX-Z\d][A-HJ-NP-Z\d]{5})$/,
168
+ /^(610[23]\d{6})$/],
169
+ excludes: []
212
170
  },
213
171
  'EASTERN' => {
214
172
  title: 'SP AusNet',
215
173
  friendly_title: 'SP AusNet DNSP',
216
174
  state: AEMO::Region.new('VIC'),
217
175
  type: 'electricity',
218
- includes: [
219
- /^(VBBB[A-HJ-NP-VX-Z\d][A-HJ-NP-Z\d]{5})$/,
220
- /^(630[56]\d{6})$/
221
- ],
222
- excludes: [
223
- ]
176
+ includes: [/^(VBBB[A-HJ-NP-VX-Z\d][A-HJ-NP-Z\d]{5})$/,
177
+ /^(630[56]\d{6})$/],
178
+ excludes: []
224
179
  },
225
180
  'POWCP' => {
226
181
  title: 'PowerCor Australia',
227
182
  friendly_title: 'PowerCor',
228
183
  state: AEMO::Region.new('VIC'),
229
184
  type: 'electricity',
230
- includes: [
231
- /^(VCCC[A-HJ-NP-VX-Z\d][A-HJ-NP-Z\d]{5})$/,
232
- /^(620[34]\d{6})$/
233
- ],
234
- excludes: [
235
- ]
185
+ includes: [/^(VCCC[A-HJ-NP-VX-Z\d][A-HJ-NP-Z\d]{5})$/,
186
+ /^(620[34]\d{6})$/],
187
+ excludes: []
236
188
  },
237
189
  'SOLARISP' => {
238
190
  title: 'Jemena Electricity Networks (VIC)',
239
191
  friendly_title: 'Jemena',
240
192
  state: AEMO::Region.new('VIC'),
241
193
  type: 'electricity',
242
- includes: [
243
- /^(VDDD[A-HJ-NP-VX-Z\d][A-HJ-NP-Z\d]{5})$/,
244
- /^(6001\d{6})$/
245
- ],
246
- excludes: [
247
- ]
194
+ includes: [/^(VDDD[A-HJ-NP-VX-Z\d][A-HJ-NP-Z\d]{5})$/,
195
+ /^(6001\d{6})$/],
196
+ excludes: []
248
197
  },
249
198
  'UNITED' => {
250
199
  title: 'United Energy Distribution',
251
200
  friendly_title: 'United Energy',
252
201
  state: AEMO::Region.new('VIC'),
253
202
  type: 'electricity',
254
- includes: [
255
- /^(VEEE[A-HJ-NP-VX-Z\d][A-HJ-NP-Z\d]{5})$/,
256
- /^(640[78]\d{6})$/
257
- ],
258
- excludes: [
259
- ]
203
+ includes: [/^(VEEE[A-HJ-NP-VX-Z\d][A-HJ-NP-Z\d]{5})$/,
204
+ /^(640[78]\d{6})$/],
205
+ excludes: []
260
206
  },
261
207
  'GPUPP' => {
262
208
  title: 'SP AusNet TNSP',
263
209
  friendly_title: 'SP AusNet TNSP',
264
210
  state: AEMO::Region.new('VIC'),
265
211
  type: 'electricity',
266
- includes: [
267
- /^(V[A-HJ-NP-Z\d]{3}W[A-HJ-NP-Z\d]{5})$/,
268
- /^(650900\d{4})$/
269
- ],
270
- excludes: [
271
- ]
212
+ includes: [/^(V[A-HJ-NP-Z\d]{3}W[A-HJ-NP-Z\d]{5})$/,
213
+ /^(650900\d{4})$/],
214
+ excludes: []
272
215
  },
273
216
  'WESTERNPOWER' => {
274
217
  title: 'Western Power',
275
218
  friendly_title: 'Western Power',
276
219
  state: AEMO::Region.new('WA'),
277
220
  type: 'electricity',
278
- includes: [
279
- /^(WAAA[A-HJ-NP-VX-Z\d][A-HJ-NP-Z\d]{5})$/,
280
- /^(800[1-9]\d{6})$/,
281
- /^(801\d{7})$/,
282
- /^(8020\d{6})$/
283
- ],
284
- excludes: [
285
- ]
221
+ includes: [/^(WAAA[A-HJ-NP-VX-Z\d][A-HJ-NP-Z\d]{5})$/,
222
+ /^(800[1-9]\d{6})$/,
223
+ /^(801\d{7})$/,
224
+ /^(8020\d{6})$/],
225
+ excludes: []
286
226
  },
287
227
  'HORIZONPOWER' => {
288
228
  title: 'Horizon Power',
289
229
  friendly_title: 'Horizon Power',
290
230
  state: AEMO::Region.new('WA'),
291
231
  type: 'electricity',
292
- includes: [
293
- /^(8021\d{6})$/
294
- ],
295
- excludes: [
296
- ]
232
+ includes: [/^(8021\d{6})$/],
233
+ excludes: []
297
234
  },
298
235
  'GAS_NSW' => {
299
236
  title: 'GAS NSW',
300
237
  friendly_title: 'GAS NSW',
301
238
  state: AEMO::Region.new('NSW'),
302
239
  type: 'gas',
303
- includes: [
304
- /^(52\d{8})$/
305
- ],
306
- excludes: [
307
- ]
240
+ includes: [/^(52\d{8})$/],
241
+ excludes: []
308
242
  },
309
243
  'GAS_VIC' => {
310
244
  title: 'GAS VIC',
311
245
  friendly_title: 'GAS VIC',
312
246
  state: AEMO::Region.new('VIC'),
313
247
  type: 'gas',
314
- includes: [
315
- /^(53\d{8})$/
316
- ],
317
- excludes: [
318
- ]
248
+ includes: [/^(53\d{8})$/],
249
+ excludes: []
319
250
  },
320
251
  'GAS_QLD' => {
321
252
  title: 'GAS QLD',
322
253
  friendly_title: 'GAS QLD',
323
254
  state: AEMO::Region.new('QLD'),
324
255
  type: 'gas',
325
- includes: [
326
- /^(54\d{8})$/
327
- ],
328
- excludes: [
329
- ]
256
+ includes: [/^(54\d{8})$/],
257
+ excludes: []
330
258
  },
331
259
  'GAS_SA' => {
332
260
  title: 'GAS SA',
333
261
  friendly_title: 'GAS SA',
334
262
  state: AEMO::Region.new('SA'),
335
263
  type: 'gas',
336
- includes: [
337
- /^(55\d{8})$/
338
- ],
339
- excludes: [
340
- ]
264
+ includes: [/^(55\d{8})$/],
265
+ excludes: []
341
266
  },
342
267
  'GAS_WA' => {
343
268
  title: 'GAS WA',
344
269
  friendly_title: 'GAS WA',
345
270
  state: AEMO::Region.new('WA'),
346
271
  type: 'gas',
347
- includes: [
348
- /^(56\d{8})$/
349
- ],
350
- excludes: [
351
- ]
272
+ includes: [/^(56\d{8})$/],
273
+ excludes: []
352
274
  },
353
275
  'GAS_TAS' => {
354
276
  title: 'GAS TAS',
355
277
  friendly_title: 'GAS TAS',
356
278
  state: AEMO::Region.new('TAS'),
357
279
  type: 'gas',
358
- includes: [
359
- /^(57\d{8})$/
360
- ],
361
- excludes: [
362
- ]
280
+ includes: [/^(57\d{8})$/],
281
+ excludes: []
363
282
  },
364
283
  'FEDAIRPORTS' => {
365
284
  title: 'Federal Airports Corporation (Sydney Airport)',
366
285
  friendly_title: 'Sydney Airport',
367
286
  state: AEMO::Region.new('NSW'),
368
287
  type: 'electricity',
369
- includes: [
370
- /^(NJJJNR[A-HJ-NP-Z\d]{4})$/
371
- ],
372
- excludes: [
373
- ]
288
+ includes: [/^(NJJJNR[A-HJ-NP-Z\d]{4})$/],
289
+ excludes: []
374
290
  },
375
291
  'EXEMPTNETWORKS' => {
376
292
  title: 'Exempt Networks - various',
377
293
  friendly_title: 'Exempt Networks - various',
378
294
  state: '',
379
295
  type: 'electricity',
380
- includes: [
381
- /^(NKKK[A-HJ-NP-VX-Z\d][A-HJ-NP-Z\d]{5})$/,
382
- /^(7102\d{6})$/
383
- ],
384
- excludes: [
385
- ]
296
+ includes: [/^(NKKK[A-HJ-NP-VX-Z\d][A-HJ-NP-Z\d]{5})$/,
297
+ /^(7102\d{6})$/],
298
+ excludes: []
386
299
  },
387
300
  'AEMORESERVED' => {
388
301
  title: 'AEMO Reserved',
389
302
  friendly_title: 'AEMO Reserved',
390
303
  state: '',
391
304
  type: 'electricity',
392
- includes: [
393
- /^(880[1-5]\d{6})$/,
394
- /^(9\d{9})$/
395
- ],
396
- excludes: [
397
- ]
305
+ includes: [/^(880[1-5]\d{6})$/,
306
+ /^(9\d{9})$/],
307
+ excludes: []
398
308
  }
399
309
  }.freeze
400
310
  # Transmission Node Identifier Codes are loaded from a json file
401
311
  # Obtained from http://www.nemweb.com.au/
402
312
  #
403
313
  # See /lib/data for further data manipulation required
404
- TNI_CODES = JSON.parse(File.read(File.join(File.dirname(__FILE__), '..', 'data', 'aemo-tni.json'))).freeze
314
+ TNI_CODES = JSON.parse(File.read(File.join(File.dirname(__FILE__), '..',
315
+ 'data', 'aemo-tni.json'))).freeze
405
316
  # Distribution Loss Factor Codes are loaded from a json file
406
- # Obtained from MSATS, matching to DNSP from file http://www.aemo.com.au/Electricity/Market-Operations/Loss-Factors-and-Regional-Boundaries/~/media/Files/Other/loss% 20factors/DLF_FINAL_V2_2014_2015.ashx
407
- # Last accessed 2015-02-06
317
+ # Obtained from MSATS, matching to DNSP from file
318
+ # https://www.aemo.com.au/-/media/Files/Electricity/NEM/
319
+ # Security_and_Reliability/Loss_Factors_and_Regional_Boundaries/
320
+ # 2016/DLF_V3_2016_2017.pdf
321
+ #
322
+ # Last accessed 2017-08-01
408
323
  # See /lib/data for further data manipulation required
409
- DLF_CODES = JSON.parse(File.read(File.join(File.dirname(__FILE__), '..', 'data', 'aemo-dlf.json'))).freeze
324
+ DLF_CODES = JSON.parse(File.read(File.join(File.dirname(__FILE__), '..',
325
+ 'data', 'aemo-dlf.json'))).freeze
410
326
 
411
327
  # [String] National Meter Identifier
412
328
  @nmi = nil
@@ -423,18 +339,24 @@ module AEMO
423
339
  @roles = nil
424
340
  @data_streams = nil
425
341
 
426
- attr_accessor :nmi, :msats_detail, :tni, :dlf, :customer_classification_code, :customer_threshold_code, :jurisdiction_code, :classification_code, :status, :address, :meters, :roles, :data_streams
342
+ attr_accessor :nmi, :msats_detail, :tni, :dlf,
343
+ :customer_classification_code, :customer_threshold_code,
344
+ :jurisdiction_code, :classification_code, :status, :address,
345
+ :meters, :roles, :data_streams
427
346
 
428
347
  # Initialize a NMI file
429
348
  #
430
349
  # @param [String] nmi the National Meter Identifier (NMI)
431
350
  # @param [Hash] options a hash of options
432
- # @option options [Hash] :msats_detail MSATS details as per #parse_msats_detail requirements
351
+ # @option options [Hash] :msats_detail MSATS details as per
352
+ # #parse_msats_detail requirements
433
353
  # @return [AEMO::NMI] an instance of AEMO::NMI is returned
434
354
  def initialize(nmi, options = {})
435
355
  raise ArgumentError, 'NMI is not a string' unless nmi.is_a?(String)
436
356
  raise ArgumentError, 'NMI is not 10 characters' unless nmi.length == 10
437
- raise ArgumentError, 'NMI is not constructed with valid characters' unless AEMO::NMI.valid_nmi?(nmi)
357
+ unless AEMO::NMI.valid_nmi?(nmi)
358
+ raise ArgumentError, 'NMI is not constructed with valid characters'
359
+ end
438
360
 
439
361
  @nmi = nmi
440
362
  @meters = []
@@ -459,17 +381,21 @@ module AEMO
459
381
  AEMO::NMI.network(@nmi)
460
382
  end
461
383
 
462
- # A function to calculate the checksum value for a given National Meter Identifier
384
+ # A function to calculate the checksum value for a given
385
+ # National Meter Identifier
463
386
  #
464
- # @param [Integer] checksum_value the checksum value to check against the current National Meter Identifier's checksum value
387
+ # @param [Integer] checksum_value the checksum value to check against the
388
+ # current National Meter Identifier's checksum value
465
389
  # @return [Boolean] whether or not the checksum is valid
466
390
  def valid_checksum?(checksum_value)
467
391
  checksum_value == checksum
468
392
  end
469
393
 
470
- # Checksum is a function to calculate the checksum value for a given National Meter Identifier
394
+ # Checksum is a function to calculate the checksum value for a given
395
+ # National Meter Identifier
471
396
  #
472
- # @return [Integer] the checksum value for the current National Meter Identifier
397
+ # @return [Integer] the checksum value for the current National Meter
398
+ # Identifier
473
399
  def checksum
474
400
  summation = 0
475
401
  @nmi.reverse.split(//).each_index do |i|
@@ -486,12 +412,14 @@ module AEMO
486
412
  #
487
413
  # @return [Hash] MSATS NMI Detail data
488
414
  def raw_msats_nmi_detail(options = {})
489
- raise ArgumentError,
490
- 'MSATS has no authentication credentials' unless AEMO::MSATS.can_authenticate?
415
+ unless AEMO::MSATS.can_authenticate?
416
+ raise ArgumentError, 'MSATS has no authentication credentials'
417
+ end
491
418
  AEMO::MSATS.nmi_detail(@nmi, options)
492
419
  end
493
420
 
494
- # Provided MSATS is configured, uses the raw MSATS data to augment NMI information
421
+ # Provided MSATS is configured, uses the raw MSATS data to augment NMI
422
+ # information
495
423
  #
496
424
  # @return [self] returns self
497
425
  def update_from_msats!(options = {})
@@ -523,27 +451,13 @@ module AEMO
523
451
  unless @msats_detail['MeterRegister'].nil?
524
452
  meters = @msats_detail['MeterRegister']['Meter']
525
453
  meters = [meters] if meters.is_a?(Hash)
526
- meters.select { |x| !x['Status'].nil? }.each do |meter|
527
- @meters << OpenStruct.new(
528
- status: meter['Status'],
529
- installation_type_code: meter['InstallationTypeCode'],
530
- next_scheduled_read_date: meter['NextScheduledReadDate'],
531
- read_type_code: meter['ReadTypeCode'],
532
- registers: [],
533
- serial_number: meter['SerialNumber']
534
- )
454
+ meters.reject { |x| x['Status'].nil? }.each do |meter|
455
+ @meters << AEMO::Meter.from_hash(meter)
535
456
  end
536
457
  meters.select { |x| x['Status'].nil? }.each do |registers|
537
458
  m = @meters.find { |x| x.serial_number == registers['SerialNumber'] }
538
- m.registers << OpenStruct.new(
539
- controlled_load: (registers['RegisterConfiguration']['Register']['ControlledLoad'] == 'Y'),
540
- dial_format: registers['RegisterConfiguration']['Register']['DialFormat'],
541
- multiplier: registers['RegisterConfiguration']['Register']['Multiplier'],
542
- network_tariff_code: registers['RegisterConfiguration']['Register']['NetworkTariffCode'],
543
- register_id: registers['RegisterConfiguration']['Register']['RegisterID'],
544
- status: registers['RegisterConfiguration']['Register']['Status'],
545
- time_of_day: registers['RegisterConfiguration']['Register']['TimeOfDay'],
546
- unit_of_measure: registers['RegisterConfiguration']['Register']['UnitOfMeasure']
459
+ m.registers << AEMO::Register.from_hash(
460
+ registers['RegisterConfiguration']['Register']
547
461
  )
548
462
  end
549
463
  end
@@ -588,10 +502,11 @@ module AEMO
588
502
  friendly_address
589
503
  end
590
504
 
591
- # Returns the meter OpenStructs for the requested status (C/R)
505
+ # Returns the meters for the requested status (C/R)
592
506
  #
593
507
  # @param [String] status the stateus [C|R]
594
- # @return [Array<OpenStruct>] Returns an array of OpenStructs for Meters with the status provided
508
+ # @return [Array<AEMO::Meter>] Returns an array of AEMO::Meters with the
509
+ # status provided
595
510
  def meters_by_status(status = 'C')
596
511
  @meters.select { |x| x.status == status.to_s }
597
512
  end
@@ -599,7 +514,8 @@ module AEMO
599
514
  # Returns the data_stream OpenStructs for the requested status (A/I)
600
515
  #
601
516
  # @param [String] status the stateus [A|I]
602
- # @return [Array<OpenStruct>] Returns an array of OpenStructs for the current Meters
517
+ # @return [Array<OpenStruct>] Returns an array of OpenStructs for the
518
+ # current Meters
603
519
  def data_streams_by_status(status = 'A')
604
520
  @data_streams.select { |x| x.status == status.to_s }
605
521
  end
@@ -608,7 +524,8 @@ module AEMO
608
524
  #
609
525
  # @return [Integer] the current daily load for the meter in kWh
610
526
  def current_daily_load
611
- data_streams_by_status.map { |x| x.averaged_daily_load.to_i }.inject(0, :+)
527
+ data_streams_by_status.map { |x| x.averaged_daily_load.to_i }
528
+ .inject(0, :+)
612
529
  end
613
530
 
614
531
  # The current annual load in MWh
@@ -626,10 +543,12 @@ module AEMO
626
543
  ((nmi.length == 10) && !nmi.match(/^([A-HJ-NP-Z\d]{10})/).nil?)
627
544
  end
628
545
 
629
- # A function to calculate the checksum value for a given National Meter Identifier
546
+ # A function to calculate the checksum value for a given National Meter
547
+ # Identifier
630
548
  #
631
549
  # @param [String] nmi the NMI to check the checksum against
632
- # @param [Integer] checksum_value the checksum value to check against the current National Meter Identifier's checksum value
550
+ # @param [Integer] checksum_value the checksum value to check against the
551
+ # current National Meter Identifier's checksum value
633
552
  # @return [Boolean] whether or not the checksum is valid
634
553
  def self.valid_checksum?(nmi, checksum_value)
635
554
  nmi = AEMO::NMI.new(nmi)
@@ -655,13 +574,20 @@ module AEMO
655
574
 
656
575
  # A function to return the distribution loss factor value for a given date
657
576
  #
658
- # @param [DateTime, Time] datetime the date for the distribution loss factor value
577
+ # @param [DateTime, Time] datetime the date for the distribution loss factor
578
+ # value
659
579
  # @return [nil, float] the distribution loss factor value
660
580
  def dlfc_value(datetime = DateTime.now)
661
- raise 'No DLF set, ensure that you have set the value either via the update_from_msats! function or manually' if @dlf.nil?
581
+ if @dlf.nil?
582
+ raise 'No DLF set, ensure that you have set the value either via the' \
583
+ 'update_from_msats! function or manually'
584
+ end
662
585
  raise 'DLF is invalid' unless DLF_CODES.keys.include?(@dlf)
663
586
  raise 'Invalid date' unless [DateTime, Time].include?(datetime.class)
664
- possible_values = DLF_CODES[@dlf].select { |x| DateTime.parse(x['FromDate']) <= datetime && datetime <= DateTime.parse(x['ToDate']) }
587
+ possible_values = DLF_CODES[@dlf].select do |x|
588
+ DateTime.parse(x['FromDate']) <= datetime &&
589
+ DateTime.parse(x['ToDate']) >= datetime
590
+ end
665
591
  if possible_values.empty?
666
592
  nil
667
593
  else