aemo 0.1.39 → 0.1.40
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/aemo.rb +4 -0
- data/lib/aemo/dispatchable.rb +2 -0
- data/lib/aemo/market.rb +17 -11
- data/lib/aemo/market/interval.rb +3 -1
- data/lib/aemo/market/node.rb +4 -2
- data/lib/aemo/meter.rb +37 -0
- data/lib/aemo/msats.rb +7 -6
- data/lib/aemo/nem12.rb +40 -40
- data/lib/aemo/nem13.rb +2 -0
- data/lib/aemo/nmi.rb +170 -244
- data/lib/aemo/region.rb +3 -1
- data/lib/aemo/register.rb +42 -0
- data/lib/aemo/version.rb +3 -1
- data/lib/data/TNI-MLF-Codes.csv +644 -564
- data/lib/data/xml_to_json.rb +27 -11
- data/spec/aemo_spec.rb +2 -0
- data/spec/lib/aemo/market/interval_spec.rb +2 -0
- data/spec/lib/aemo/market/node_spec.rb +2 -0
- data/spec/lib/aemo/market_spec.rb +3 -1
- data/spec/lib/aemo/meter_spec.rb +18 -0
- data/spec/lib/aemo/msats_spec.rb +2 -0
- data/spec/lib/aemo/nem12_spec.rb +21 -1
- data/spec/lib/aemo/nmi_spec.rb +4 -1
- data/spec/lib/aemo/region_spec.rb +2 -0
- data/spec/spec_helper.rb +10 -0
- metadata +22 -38
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 99c92027fe76a3d8367716e2274157b9239c48ee
|
4
|
+
data.tar.gz: 70d04cf7ed134fc1ac3aab96d8727e043c19104b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
data/lib/aemo/dispatchable.rb
CHANGED
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>]
|
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>]
|
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 } }
|
48
|
-
|
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
|
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
|
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 =
|
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(
|
68
|
-
|
69
|
-
values
|
74
|
+
response = HTTParty.get(url)
|
75
|
+
parse_response(response)
|
70
76
|
end
|
71
77
|
|
72
78
|
protected
|
data/lib/aemo/market/interval.rb
CHANGED
@@ -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]
|
data/lib/aemo/market/node.rb
CHANGED
@@ -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
|
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.
|
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
|
-
|
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
|
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
|
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
|
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
|
96
|
-
12 => { type: %w
|
97
|
-
13 => { type: %w
|
98
|
-
14 => { type: %w
|
99
|
-
15 => { type: %w
|
100
|
-
16 => { type: %w
|
101
|
-
17 => { type: %w
|
102
|
-
18 => { type: %w
|
103
|
-
19 => { type: %w
|
104
|
-
51 => { type: %w
|
105
|
-
52 => { type: %w
|
106
|
-
53 => { type: %w
|
107
|
-
54 => { type: %w
|
108
|
-
55 => { type: %w
|
109
|
-
56 => { type: %w
|
110
|
-
57 => { type: %w
|
111
|
-
58 => { type: %w
|
112
|
-
61 => { type: %w
|
113
|
-
62 => { type: %w
|
114
|
-
63 => { type: %w
|
115
|
-
64 => { type: %w
|
116
|
-
65 => { type: %w
|
117
|
-
66 => { type: %w
|
118
|
-
67 => { type: %w
|
119
|
-
68 => { type: %w
|
120
|
-
71 => { type: %w
|
121
|
-
72 => { type: %w
|
122
|
-
73 => { type: %w
|
123
|
-
74 => { type: %w
|
124
|
-
75 => { type: %w
|
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
|
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
|
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
|
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
|
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
|
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
|
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
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
|
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
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
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
|
21
|
-
#
|
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
|
-
|
30
|
-
|
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
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
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
|
-
|
60
|
-
|
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
|
-
|
72
|
-
|
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
|
-
|
84
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
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
|
-
|
135
|
-
|
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
|
-
|
147
|
-
|
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
|
-
|
159
|
-
|
160
|
-
|
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
|
-
|
172
|
-
|
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
|
-
|
184
|
-
|
185
|
-
|
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
|
-
|
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
|
-
|
208
|
-
|
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
|
-
|
220
|
-
|
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
|
-
|
232
|
-
|
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
|
-
|
244
|
-
|
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
|
-
|
256
|
-
|
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
|
-
|
268
|
-
|
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
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
382
|
-
|
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
|
-
|
394
|
-
|
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__), '..',
|
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
|
407
|
-
#
|
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__), '..',
|
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,
|
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
|
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
|
-
|
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
|
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
|
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
|
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
|
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
|
-
|
490
|
-
|
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
|
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.
|
527
|
-
@meters <<
|
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 <<
|
539
|
-
|
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
|
505
|
+
# Returns the meters for the requested status (C/R)
|
592
506
|
#
|
593
507
|
# @param [String] status the stateus [C|R]
|
594
|
-
# @return [Array<
|
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
|
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 }
|
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
|
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
|
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
|
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
|
-
|
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
|
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
|