aemo 0.2.1 → 0.3.0.pre.rc1
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 +4 -4
- data/lib/aemo/exceptions/invalid_nmi_allocation_type.rb +21 -0
- data/lib/aemo/market/interval.rb +1 -3
- data/lib/aemo/market/node.rb +1 -3
- data/lib/aemo/market.rb +2 -2
- data/lib/aemo/nem12.rb +9 -27
- data/lib/aemo/nmi/allocation.rb +468 -0
- data/lib/aemo/nmi.rb +93 -359
- data/lib/aemo/version.rb +1 -1
- data/lib/aemo.rb +2 -0
- data/lib/data/xml_to_json.rb +4 -4
- data/spec/lib/aemo/market/interval_spec.rb +3 -3
- data/spec/lib/aemo/msats_spec.rb +4 -8
- data/spec/lib/aemo/nmi/allocation_spec.rb +50 -0
- data/spec/lib/aemo/nmi_spec.rb +16 -8
- metadata +43 -39
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f959b4ca7bb32fece4066d2cb2bd6efe309cf1dcefd9c602d9589d175b0e082e
|
4
|
+
data.tar.gz: e3a4a60539a8b97b557b751c1a65df03ddf6f301f12e596a20d7440ab44648d2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e75333c5f79fda5575ddcf30103d449b518405f500cd72fb929fc69e3f56f03d7eafdc56e8afad90c47ac092db77991b87bcf6f9cf29d08e2f40ffa97dc24f80
|
7
|
+
data.tar.gz: 203aa713e569e35896b8d4b1ae85df3581ef2f1fbf1c42a75a67557a7264f47a36c51f2ae9b66eff1b5077f24050ac6c7a6cd631e683ce8e4cf4f643d1ace645
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AEMO
|
4
|
+
# AEMO::InvalidNMIAllocationType
|
5
|
+
#
|
6
|
+
# @author Stuart Auld
|
7
|
+
# @abstract An exception representing an invalid NMI allocation type
|
8
|
+
# @since 0.3.0
|
9
|
+
class InvalidNMIAllocationType < ArgumentError
|
10
|
+
DEFAULT_MESSAGE = 'Not a valid allocation type, try one of ' \
|
11
|
+
"#{AEMO::NMI::Allocation::SUPPORTED_TYPES.join(' |')}"
|
12
|
+
|
13
|
+
# Initialize an InvalidNMIAllocationType
|
14
|
+
#
|
15
|
+
# @param [String] msg the error message
|
16
|
+
# @return [AEMO::InvalidNMIAllocationType]
|
17
|
+
def initialize(msg = DEFAULT_MESSAGE)
|
18
|
+
super
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/aemo/market/interval.rb
CHANGED
@@ -72,9 +72,7 @@ module AEMO
|
|
72
72
|
# @return [Float] the value of the interval in Australian Dollars
|
73
73
|
def value
|
74
74
|
@value ||= Float::NAN
|
75
|
-
if @total_demand.class == Float && @rrp.class == Float
|
76
|
-
@value = (@total_demand * @rrp).round(2)
|
77
|
-
end
|
75
|
+
@value = (@total_demand * @rrp).round(2) if @total_demand.class == Float && @rrp.class == Float
|
78
76
|
@value
|
79
77
|
end
|
80
78
|
end
|
data/lib/aemo/market/node.rb
CHANGED
@@ -23,9 +23,7 @@ module AEMO
|
|
23
23
|
#
|
24
24
|
# @return [Array<AEMO::Market::Interval>]
|
25
25
|
def current_dispatch
|
26
|
-
if @current_dispatch.empty? || @current_dispatch.last.datetime != (Time.now - Time.now.to_i % 300)
|
27
|
-
@current_dispatch = AEMO::Market.current_dispatch(@identifier)
|
28
|
-
end
|
26
|
+
@current_dispatch = AEMO::Market.current_dispatch(@identifier) if @current_dispatch.empty? || @current_dispatch.last.datetime != (Time.now - Time.now.to_i % 300)
|
29
27
|
@current_dispatch
|
30
28
|
end
|
31
29
|
|
data/lib/aemo/market.rb
CHANGED
@@ -39,8 +39,8 @@ module AEMO
|
|
39
39
|
# Return an array of historic trading values based on a start and finish
|
40
40
|
#
|
41
41
|
# @param [String, AEMO::Region] region AEMO::Region
|
42
|
-
# @param [
|
43
|
-
# @param [
|
42
|
+
# @param [Time] start this is inclusive not exclusive
|
43
|
+
# @param [Time] finish this is inclusive not exclusive
|
44
44
|
# @return [Array<AEMO::Market::Interval>]
|
45
45
|
def historic_trading_by_range(region, start, finish)
|
46
46
|
region = AEMO::Region.new(region) if region.is_a?(String)
|
data/lib/aemo/nem12.rb
CHANGED
@@ -297,9 +297,7 @@ module AEMO
|
|
297
297
|
|
298
298
|
raise ArgumentError, 'RecordIndicator is not 100' if csv[0] != '100'
|
299
299
|
raise ArgumentError, 'VersionHeader is not NEM12' if csv[1] != 'NEM12'
|
300
|
-
if options[:strict] && (csv[2].match(/\d{12}/).nil? || csv[2] != Time.parse("#{csv[2]}00").strftime('%Y%m%d%H%M'))
|
301
|
-
raise ArgumentError, 'DateTime is not valid'
|
302
|
-
end
|
300
|
+
raise ArgumentError, 'Time is not valid' if options[:strict] && (csv[2].match(/\d{12}/).nil? || csv[2] != Time.parse("#{csv[2]}00").strftime('%Y%m%d%H%M'))
|
303
301
|
raise ArgumentError, 'FromParticipant is not valid' if csv[3].match(/.{1,10}/).nil?
|
304
302
|
raise ArgumentError, 'ToParticipant is not valid' if csv[4].match(/.{1,10}/).nil?
|
305
303
|
|
@@ -320,24 +318,12 @@ module AEMO
|
|
320
318
|
|
321
319
|
raise ArgumentError, 'RecordIndicator is not 200' if csv[0] != '200'
|
322
320
|
raise ArgumentError, 'NMI is not valid' unless AEMO::NMI.valid_nmi?(csv[1])
|
323
|
-
if options[:strict] && (csv[2].nil? || csv[2].match(/.{1,240}/).nil?)
|
324
|
-
|
325
|
-
|
326
|
-
if !csv[
|
327
|
-
|
328
|
-
|
329
|
-
if csv[4].nil? || csv[4].match(/[A-HJ-NP-Z][1-9A-HJ-NP-Z]/).nil?
|
330
|
-
raise ArgumentError, 'NMISuffix is not valid'
|
331
|
-
end
|
332
|
-
if !csv[5].nil? && !csv[5].empty? && !csv[5].match(/^\s*$/)
|
333
|
-
raise ArgumentError, 'MDMDataStreamIdentifier is not valid' if csv[5].match(/[A-Z0-9]{2}/).nil?
|
334
|
-
end
|
335
|
-
if !csv[6].nil? && !csv[6].empty? && !csv[6].match(/^\s*$/)
|
336
|
-
raise ArgumentError, 'MeterSerialNumber is not valid' if csv[6].match(/[A-Z0-9]{2}/).nil?
|
337
|
-
end
|
338
|
-
if csv[7].nil? || csv[7].upcase.match(/[A-Z0-9]{2}/).nil?
|
339
|
-
raise ArgumentError, 'UOM is not valid'
|
340
|
-
end
|
321
|
+
raise ArgumentError, 'NMIConfiguration is not valid' if options[:strict] && (csv[2].nil? || csv[2].match(/.{1,240}/).nil?)
|
322
|
+
raise ArgumentError, 'RegisterID is not valid' if !csv[3].nil? && csv[3].match(/.{1,10}/).nil?
|
323
|
+
raise ArgumentError, 'NMISuffix is not valid' if csv[4].nil? || csv[4].match(/[A-HJ-NP-Z][1-9A-HJ-NP-Z]/).nil?
|
324
|
+
raise ArgumentError, 'MDMDataStreamIdentifier is not valid' if !csv[5].nil? && !csv[5].empty? && !csv[5].match(/^\s*$/) && csv[5].match(/[A-Z0-9]{2}/).nil?
|
325
|
+
raise ArgumentError, 'MeterSerialNumber is not valid' if !csv[6].nil? && !csv[6].empty? && !csv[6].match(/^\s*$/) && csv[6].match(/[A-Z0-9]{2}/).nil?
|
326
|
+
raise ArgumentError, 'UOM is not valid' if csv[7].nil? || csv[7].upcase.match(/[A-Z0-9]{2}/).nil?
|
341
327
|
raise ArgumentError, 'UOM is not valid' unless UOM.keys.map(&:upcase).include?(csv[7].upcase)
|
342
328
|
raise ArgumentError, 'IntervalLength is not valid' unless %w[1 5 10 15 30].include?(csv[8])
|
343
329
|
# raise ArgumentError, 'NextScheduledReadDate is not valid' if csv[9].match(/\d{8}/).nil? || csv[9] != Time.parse('#{csv[9]}').strftime('%Y%m%d')
|
@@ -404,9 +390,7 @@ module AEMO
|
|
404
390
|
flag[:quality_flag] = csv[intervals_offset + 0][0]
|
405
391
|
flag[:method_flag] = csv[intervals_offset + 0][1, 2].to_i
|
406
392
|
end
|
407
|
-
unless csv[intervals_offset + 1].nil?
|
408
|
-
flag[:reason_code] = csv[intervals_offset + 1].to_i
|
409
|
-
end
|
393
|
+
flag[:reason_code] = csv[intervals_offset + 1].to_i unless csv[intervals_offset + 1].nil?
|
410
394
|
end
|
411
395
|
|
412
396
|
base_interval = { data_details: @data_details.last, datetime: Time.parse("#{csv[1]}000000+1000"), value: nil, flag: flag }
|
@@ -454,9 +438,7 @@ module AEMO
|
|
454
438
|
flag[:quality_flag] = interval_event[:quality_method][0]
|
455
439
|
flag[:method_flag] = interval_event[:quality_method][1, 2].to_i
|
456
440
|
end
|
457
|
-
unless interval_event[:reason_code].nil?
|
458
|
-
flag[:reason_code] = interval_event[:reason_code]
|
459
|
-
end
|
441
|
+
flag[:reason_code] = interval_event[:reason_code] unless interval_event[:reason_code].nil?
|
460
442
|
# Update with flag details
|
461
443
|
@interval_data[interval_start_point + (i - 1)][:flag] = flag
|
462
444
|
end
|
@@ -0,0 +1,468 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AEMO
|
4
|
+
class NMI
|
5
|
+
# [AEMO::NMI::Allocation]
|
6
|
+
#
|
7
|
+
# @author Joel Courtney
|
8
|
+
# @author Stuart Auld
|
9
|
+
# @abstract An abstraction of NMI Allocation groups that kind of represents
|
10
|
+
# networks but not always.
|
11
|
+
# @since 0.3.0
|
12
|
+
#
|
13
|
+
# @attr [Array<Regexp>] exclude_nmi_patterns
|
14
|
+
# @attr [String] friendly_title
|
15
|
+
# @attr [String] identifier
|
16
|
+
# @attr [Array<Regexp>] include_nmi_patterns
|
17
|
+
# @attr [AEMO::Region] region
|
18
|
+
# @attr [String] title
|
19
|
+
# @attr [Symbol] type
|
20
|
+
class Allocation
|
21
|
+
# NMI_ALLOCATIONS as per AEMO Documentation at
|
22
|
+
# https://www.aemo.com.au/-/media/Files/Electricity/NEM/Retail_and_Metering/Metering-Procedures/NMI-Allocation-List.pdf
|
23
|
+
# Last updated 2017-08-01
|
24
|
+
ALLOCATIONS = [
|
25
|
+
{
|
26
|
+
participant_id: 'ACTEWP',
|
27
|
+
title: 'Actew Distribution Ltd and Jemena Networks (ACT) Pty Ltd',
|
28
|
+
friendly_title: 'ACTEWAgl',
|
29
|
+
region: 'ACT',
|
30
|
+
type: 'electricity',
|
31
|
+
includes: [
|
32
|
+
/^(NGGG[A-HJ-NP-VX-Z\d][A-HJ-NP-Z\d]{5})$/,
|
33
|
+
/^(7001\d{6})$/
|
34
|
+
],
|
35
|
+
excludes: []
|
36
|
+
},
|
37
|
+
{
|
38
|
+
participant_id: 'CNRGYP',
|
39
|
+
title: 'Essential Energy',
|
40
|
+
friendly_title: 'Essential Energy',
|
41
|
+
region: 'NSW',
|
42
|
+
type: 'electricity',
|
43
|
+
includes: [
|
44
|
+
/^(NAAA[A-HJ-NP-VX-Z\d][A-HJ-NP-Z\d]{5})$/,
|
45
|
+
/^(NBBB[A-HJ-NP-VX-Z\d][A-HJ-NP-Z\d]{5})$/,
|
46
|
+
/^(NDDD[A-HJ-NP-VX-Z\d][A-HJ-NP-Z\d]{5})$/,
|
47
|
+
/^(NFFF[A-HJ-NP-VX-Z\d][A-HJ-NP-Z\d]{5})$/,
|
48
|
+
/^(4001\d{6})$/,
|
49
|
+
/^(4508\d{6})$/,
|
50
|
+
/^(4204\d{6})$/,
|
51
|
+
/^(4407\d{6})$/
|
52
|
+
],
|
53
|
+
excludes: []
|
54
|
+
},
|
55
|
+
{
|
56
|
+
participant_id: 'ENERGYAP',
|
57
|
+
title: 'Ausgrid',
|
58
|
+
friendly_title: 'Ausgrid',
|
59
|
+
region: 'NSW',
|
60
|
+
type: 'electricity',
|
61
|
+
includes: [
|
62
|
+
/^(NCCC[A-HJ-NP-VX-Z\d][A-HJ-NP-Z\d]{5})$/,
|
63
|
+
/^(410[234]\d{6})$/
|
64
|
+
],
|
65
|
+
excludes: []
|
66
|
+
},
|
67
|
+
{
|
68
|
+
participant_id: 'INTEGP',
|
69
|
+
title: 'Endeavour Energy',
|
70
|
+
friendly_title: 'Endeavour Energy',
|
71
|
+
region: 'NSW',
|
72
|
+
type: 'electricity',
|
73
|
+
includes: [
|
74
|
+
/^(NEEE[A-HJ-NP-VX-Z\d][A-HJ-NP-Z\d]{5})$/,
|
75
|
+
/^(431\d{7})$/
|
76
|
+
],
|
77
|
+
excludes: []
|
78
|
+
},
|
79
|
+
{
|
80
|
+
participant_id: 'TRANSGP',
|
81
|
+
title: 'TransGrid',
|
82
|
+
friendly_title: 'TransGrid',
|
83
|
+
region: 'NSW',
|
84
|
+
type: 'electricity',
|
85
|
+
includes: [
|
86
|
+
/^(NTTT[A-HJ-NP-VX-Z\d][A-HJ-NP-Z\d]{5})$/,
|
87
|
+
/^(460810[0-8]\d{3})$/
|
88
|
+
],
|
89
|
+
excludes: []
|
90
|
+
},
|
91
|
+
{
|
92
|
+
participant_id: 'SNOWY',
|
93
|
+
title: 'Snowy Hydro Ltd',
|
94
|
+
friendly_title: 'Snowy Hydro',
|
95
|
+
region: 'NSW',
|
96
|
+
type: 'electricity',
|
97
|
+
includes: [/^(4708109\d{3})$/],
|
98
|
+
excludes: []
|
99
|
+
},
|
100
|
+
{
|
101
|
+
participant_id: 'NT_RESERVED',
|
102
|
+
title: 'Northern Territory Reserved Block',
|
103
|
+
friendly_title: 'Northern Territory Reserved Block',
|
104
|
+
region: 'NT',
|
105
|
+
type: 'electricity',
|
106
|
+
includes: [/^(250\d{7})$/],
|
107
|
+
excludes: []
|
108
|
+
},
|
109
|
+
{
|
110
|
+
participant_id: 'ERGONETP',
|
111
|
+
title: 'Ergon Energy Corporation',
|
112
|
+
friendly_title: 'Ergon Energy',
|
113
|
+
region: 'QLD',
|
114
|
+
type: 'electricity',
|
115
|
+
includes: [
|
116
|
+
/^(QAAA[A-HJ-NP-VX-Z\d][A-HJ-NP-Z\d]{5})$/,
|
117
|
+
/^(QCCC[A-HJ-NP-VX-Z\d][A-HJ-NP-Z\d]{5})$/,
|
118
|
+
/^(QDDD[A-HJ-NP-VX-Z\d][A-HJ-NP-Z\d]{5})$/,
|
119
|
+
/^(QEEE[A-HJ-NP-VX-Z\d][A-HJ-NP-Z\d]{5})$/,
|
120
|
+
/^(QFFF[A-HJ-NP-VX-Z\d][A-HJ-NP-Z\d]{5})$/,
|
121
|
+
/^(QGGG[A-HJ-NP-VX-Z\d][A-HJ-NP-Z\d]{5})$/,
|
122
|
+
/^(30\d{8})$/
|
123
|
+
],
|
124
|
+
excludes: []
|
125
|
+
},
|
126
|
+
{
|
127
|
+
participant_id: 'ENERGEXP',
|
128
|
+
title: 'ENERGEX Limited',
|
129
|
+
friendly_title: 'Energex',
|
130
|
+
region: 'QLD',
|
131
|
+
type: 'electricity',
|
132
|
+
includes: [
|
133
|
+
/^(QB\d{2}[A-HJ-NP-VX-Z\d][A-HJ-NP-Z\d]{5})$/,
|
134
|
+
/^(31\d{8})$/
|
135
|
+
],
|
136
|
+
excludes: []
|
137
|
+
},
|
138
|
+
{
|
139
|
+
participant_id: 'PLINKP',
|
140
|
+
title: 'Qld Electricity Transmission Corp (Powerlink)',
|
141
|
+
friendly_title: 'Powerlink',
|
142
|
+
region: 'QLD',
|
143
|
+
type: 'electricity',
|
144
|
+
includes: [
|
145
|
+
/^(Q[A-HJ-NP-Z\d]{3}W[A-HJ-NP-Z\d]{5})$/,
|
146
|
+
/^(320200\d{4})$/
|
147
|
+
],
|
148
|
+
excludes: []
|
149
|
+
},
|
150
|
+
{
|
151
|
+
participant_id: 'UMPLP',
|
152
|
+
title: 'SA Power Networks',
|
153
|
+
friendly_title: 'SA Power Networks',
|
154
|
+
region: 'SA',
|
155
|
+
type: 'electricity',
|
156
|
+
includes: [
|
157
|
+
/^(SAAA[A-HJ-NP-VX-Z\d][A-HJ-NP-Z\d]{5})$/,
|
158
|
+
/^(SASMPL[\d]{4})$/,
|
159
|
+
/^(200[12]\d{6})$/
|
160
|
+
],
|
161
|
+
excludes: []
|
162
|
+
},
|
163
|
+
{
|
164
|
+
participant_id: 'ETSATP',
|
165
|
+
title: 'ElectraNet SA',
|
166
|
+
friendly_title: 'ElectraNet SA',
|
167
|
+
region: 'SA',
|
168
|
+
type: 'electricity',
|
169
|
+
includes: [
|
170
|
+
/^(S[A-HJ-NP-Z\d]{3}W[A-HJ-NP-Z\d]{5})$/,
|
171
|
+
/^(210200\d{4})$/
|
172
|
+
],
|
173
|
+
excludes: []
|
174
|
+
},
|
175
|
+
{
|
176
|
+
participant_id: 'AURORAP',
|
177
|
+
title: 'TasNetworks',
|
178
|
+
friendly_title: 'TasNetworks',
|
179
|
+
region: 'TAS',
|
180
|
+
type: 'electricity',
|
181
|
+
includes: [
|
182
|
+
/^(T000000(([0-4]\d{3})|(500[01])))$/,
|
183
|
+
/^(8000\d{6})$/,
|
184
|
+
/^(8590[23]\d{5})$/
|
185
|
+
],
|
186
|
+
excludes: []
|
187
|
+
},
|
188
|
+
{
|
189
|
+
participant_id: 'TRANSEND',
|
190
|
+
title: 'TasNetworks',
|
191
|
+
friendly_title: 'TasNetworks',
|
192
|
+
region: 'TAS',
|
193
|
+
type: 'electricity',
|
194
|
+
includes: [/^(T[A-HJ-NP-Z\d]{3}W[A-HJ-NP-Z\d]{5})$/],
|
195
|
+
excludes: []
|
196
|
+
},
|
197
|
+
{
|
198
|
+
participant_id: 'CITIPP',
|
199
|
+
title: 'CitiPower',
|
200
|
+
friendly_title: 'CitiPower',
|
201
|
+
region: 'VIC',
|
202
|
+
type: 'electricity',
|
203
|
+
includes: [
|
204
|
+
/^(VAAA[A-HJ-NP-VX-Z\d][A-HJ-NP-Z\d]{5})$/,
|
205
|
+
/^(610[23]\d{6})$/
|
206
|
+
],
|
207
|
+
excludes: []
|
208
|
+
},
|
209
|
+
{
|
210
|
+
participant_id: 'EASTERN',
|
211
|
+
title: 'SP AusNet',
|
212
|
+
friendly_title: 'SP AusNet DNSP',
|
213
|
+
region: 'VIC',
|
214
|
+
type: 'electricity',
|
215
|
+
includes: [
|
216
|
+
/^(VBBB[A-HJ-NP-VX-Z\d][A-HJ-NP-Z\d]{5})$/,
|
217
|
+
/^(630[56]\d{6})$/
|
218
|
+
],
|
219
|
+
excludes: []
|
220
|
+
},
|
221
|
+
{
|
222
|
+
participant_id: 'POWCP',
|
223
|
+
title: 'PowerCor Australia',
|
224
|
+
friendly_title: 'PowerCor',
|
225
|
+
region: 'VIC',
|
226
|
+
type: 'electricity',
|
227
|
+
includes: [
|
228
|
+
/^(VCCC[A-HJ-NP-VX-Z\d][A-HJ-NP-Z\d]{5})$/,
|
229
|
+
/^(620[34]\d{6})$/
|
230
|
+
],
|
231
|
+
excludes: []
|
232
|
+
},
|
233
|
+
{
|
234
|
+
participant_id: 'SOLARISP',
|
235
|
+
title: 'Jemena Electricity Networks (VIC)',
|
236
|
+
friendly_title: 'Jemena',
|
237
|
+
region: 'VIC',
|
238
|
+
type: 'electricity',
|
239
|
+
includes: [
|
240
|
+
/^(VDDD[A-HJ-NP-VX-Z\d][A-HJ-NP-Z\d]{5})$/,
|
241
|
+
/^(6001\d{6})$/
|
242
|
+
],
|
243
|
+
excludes: []
|
244
|
+
},
|
245
|
+
{
|
246
|
+
participant_id: 'UNITED',
|
247
|
+
title: 'United Energy Distribution',
|
248
|
+
friendly_title: 'United Energy',
|
249
|
+
region: 'VIC',
|
250
|
+
type: 'electricity',
|
251
|
+
includes: [
|
252
|
+
/^(VEEE[A-HJ-NP-VX-Z\d][A-HJ-NP-Z\d]{5})$/,
|
253
|
+
/^(640[78]\d{6})$/
|
254
|
+
],
|
255
|
+
excludes: []
|
256
|
+
},
|
257
|
+
{
|
258
|
+
participant_id: 'GPUPP',
|
259
|
+
title: 'SP AusNet TNSP',
|
260
|
+
friendly_title: 'SP AusNet TNSP',
|
261
|
+
region: 'VIC',
|
262
|
+
type: 'electricity',
|
263
|
+
includes: [
|
264
|
+
/^(V[A-HJ-NP-Z\d]{3}W[A-HJ-NP-Z\d]{5})$/,
|
265
|
+
/^(650900\d{4})$/
|
266
|
+
],
|
267
|
+
excludes: []
|
268
|
+
},
|
269
|
+
{
|
270
|
+
participant_id: 'WESTERNPOWER',
|
271
|
+
title: 'Western Power',
|
272
|
+
friendly_title: 'Western Power',
|
273
|
+
region: 'WA',
|
274
|
+
type: 'electricity',
|
275
|
+
includes: [
|
276
|
+
/^(WAAA[A-HJ-NP-VX-Z\d][A-HJ-NP-Z\d]{5})$/,
|
277
|
+
/^(800[1-9]\d{6})$/,
|
278
|
+
/^(801\d{7})$/,
|
279
|
+
/^(8020\d{6})$/
|
280
|
+
],
|
281
|
+
excludes: []
|
282
|
+
},
|
283
|
+
{
|
284
|
+
participant_id: 'HORIZONPOWER',
|
285
|
+
title: 'Horizon Power',
|
286
|
+
friendly_title: 'Horizon Power',
|
287
|
+
region: 'WA',
|
288
|
+
type: 'electricity',
|
289
|
+
includes: [/^(8021\d{6})$/],
|
290
|
+
excludes: []
|
291
|
+
},
|
292
|
+
{
|
293
|
+
participant_id: 'GAS_NSW',
|
294
|
+
title: 'GAS NSW',
|
295
|
+
friendly_title: 'GAS NSW',
|
296
|
+
region: 'NSW',
|
297
|
+
type: 'gas',
|
298
|
+
includes: [/^(52\d{8})$/],
|
299
|
+
excludes: []
|
300
|
+
},
|
301
|
+
{
|
302
|
+
participant_id: 'GAS_VIC',
|
303
|
+
title: 'GAS VIC',
|
304
|
+
friendly_title: 'GAS VIC',
|
305
|
+
region: 'VIC',
|
306
|
+
type: 'gas',
|
307
|
+
includes: [/^(53\d{8})$/],
|
308
|
+
excludes: []
|
309
|
+
},
|
310
|
+
{
|
311
|
+
participant_id: 'GAS_QLD',
|
312
|
+
title: 'GAS QLD',
|
313
|
+
friendly_title: 'GAS QLD',
|
314
|
+
region: 'QLD',
|
315
|
+
type: 'gas',
|
316
|
+
includes: [/^(54\d{8})$/],
|
317
|
+
excludes: []
|
318
|
+
},
|
319
|
+
{
|
320
|
+
participant_id: 'GAS_SA',
|
321
|
+
title: 'GAS SA',
|
322
|
+
friendly_title: 'GAS SA',
|
323
|
+
region: 'SA',
|
324
|
+
type: 'gas',
|
325
|
+
includes: [/^(55\d{8})$/],
|
326
|
+
excludes: []
|
327
|
+
},
|
328
|
+
{
|
329
|
+
participant_id: 'GAS_WA',
|
330
|
+
title: 'GAS WA',
|
331
|
+
friendly_title: 'GAS WA',
|
332
|
+
region: 'WA',
|
333
|
+
type: 'gas',
|
334
|
+
includes: [/^(56\d{8})$/],
|
335
|
+
excludes: []
|
336
|
+
},
|
337
|
+
{
|
338
|
+
participant_id: 'GAS_TAS',
|
339
|
+
title: 'GAS TAS',
|
340
|
+
friendly_title: 'GAS TAS',
|
341
|
+
region: 'TAS',
|
342
|
+
type: 'gas',
|
343
|
+
includes: [/^(57\d{8})$/],
|
344
|
+
excludes: []
|
345
|
+
},
|
346
|
+
{
|
347
|
+
participant_id: 'FEDAIRPORTS',
|
348
|
+
title: 'Federal Airports Corporation (Sydney Airport)',
|
349
|
+
friendly_title: 'Sydney Airport',
|
350
|
+
region: 'NSW',
|
351
|
+
type: 'electricity',
|
352
|
+
includes: [/^(NJJJNR[A-HJ-NP-Z\d]{4})$/],
|
353
|
+
excludes: []
|
354
|
+
},
|
355
|
+
{
|
356
|
+
participant_id: 'EXEMPTNETWORKS',
|
357
|
+
title: 'Exempt Networks - various',
|
358
|
+
friendly_title: 'Exempt Networks - various',
|
359
|
+
type: 'electricity',
|
360
|
+
includes: [
|
361
|
+
/^(NKKK[A-HJ-NP-VX-Z\d][A-HJ-NP-Z\d]{5})$/,
|
362
|
+
/^(7102\d{6})$/
|
363
|
+
],
|
364
|
+
excludes: []
|
365
|
+
},
|
366
|
+
{
|
367
|
+
participant_id: 'AEMORESERVED',
|
368
|
+
title: 'AEMO Reserved',
|
369
|
+
friendly_title: 'AEMO Reserved',
|
370
|
+
type: 'electricity',
|
371
|
+
includes: [
|
372
|
+
/^(880[1-5]\d{6})$/,
|
373
|
+
/^(9\d{9})$/
|
374
|
+
],
|
375
|
+
excludes: []
|
376
|
+
}
|
377
|
+
].freeze
|
378
|
+
|
379
|
+
# NMI Allocations are only for Electricity and Gas metering
|
380
|
+
SUPPORTED_TYPES = %i[electricity gas].freeze
|
381
|
+
|
382
|
+
attr_accessor :exclude_nmi_patterns,
|
383
|
+
:friendly_title,
|
384
|
+
:identifier,
|
385
|
+
:include_nmi_patterns,
|
386
|
+
:region,
|
387
|
+
:title,
|
388
|
+
:type
|
389
|
+
|
390
|
+
alias state region
|
391
|
+
alias state= region=
|
392
|
+
|
393
|
+
class << self
|
394
|
+
include Enumerable
|
395
|
+
|
396
|
+
# Return all the NMI allocations
|
397
|
+
#
|
398
|
+
# @return [Array<AEMO::NMI::Allocation>]
|
399
|
+
def all
|
400
|
+
ALLOCATIONS.map do |a|
|
401
|
+
new(a.fetch(:title), a.fetch(:type), a)
|
402
|
+
end
|
403
|
+
end
|
404
|
+
|
405
|
+
# Enumerable support
|
406
|
+
#
|
407
|
+
# @return [Enumerator]
|
408
|
+
def each(&block)
|
409
|
+
all.each(&block)
|
410
|
+
end
|
411
|
+
|
412
|
+
# Finds the Allocation that encompasses a given NMI
|
413
|
+
#
|
414
|
+
# @param [string] nmi
|
415
|
+
# @return [AEMO::NMI::Allocation]
|
416
|
+
def find_by_nmi(nmi)
|
417
|
+
each do |allocation|
|
418
|
+
allocation.exclude_nmi_patterns.each do |pattern|
|
419
|
+
next if nmi.match(pattern)
|
420
|
+
end
|
421
|
+
allocation.include_nmi_patterns.each do |pattern|
|
422
|
+
return allocation if nmi.match(pattern)
|
423
|
+
end
|
424
|
+
end
|
425
|
+
nil
|
426
|
+
end
|
427
|
+
end
|
428
|
+
|
429
|
+
# Initialises an {AEMO::NMI::Allocation}
|
430
|
+
#
|
431
|
+
# @param [String] title
|
432
|
+
# @param [String] type
|
433
|
+
# @param [Hash] opts
|
434
|
+
# @option opts [String] :identifier
|
435
|
+
# @option opts [String] :friendly_title
|
436
|
+
# @option opts [Array<Regexp>] :exclude_nmi_patterns
|
437
|
+
# @option opts [Array<Regexp>] :include_nmi_patterns
|
438
|
+
# @option opts [String] :region
|
439
|
+
# @return [AEMO::NMI::Allocation]
|
440
|
+
def initialize(title, type, opts = {})
|
441
|
+
@title = title
|
442
|
+
@type = parse_allocation_type(type)
|
443
|
+
@identifier = opts.fetch(:identifier, title.upcase)
|
444
|
+
@friendly_title = opts.fetch(:friendly_title, title)
|
445
|
+
@exclude_nmi_patterns = opts.fetch(:excludes, [])
|
446
|
+
@include_nmi_patterns = opts.fetch(:includes, [])
|
447
|
+
@region = AEMO::Region.new(opts.fetch(:region)) if opts.dig(:region)
|
448
|
+
end
|
449
|
+
|
450
|
+
private
|
451
|
+
|
452
|
+
# Private method to parse an
|
453
|
+
#
|
454
|
+
# @param [#to_sym] type
|
455
|
+
# @raise [AEMO::InvalidNMIAllocationType]
|
456
|
+
# @return [Symbol]
|
457
|
+
def parse_allocation_type(type)
|
458
|
+
type_sym = type.to_sym
|
459
|
+
unless SUPPORTED_TYPES.include?(type_sym)
|
460
|
+
raise AEMO::InvalidNMIAllocationType
|
461
|
+
end
|
462
|
+
type_sym
|
463
|
+
rescue NoMethodError
|
464
|
+
raise AEMO::InvalidNMIAllocationType
|
465
|
+
end
|
466
|
+
end
|
467
|
+
end
|
468
|
+
end
|