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.
data/lib/aemo/nmi.rb CHANGED
@@ -4,315 +4,39 @@ require 'csv'
4
4
  require 'json'
5
5
  require 'time'
6
6
  require 'ostruct'
7
+
7
8
  module AEMO
9
+ # [AEMO::NMI]
10
+ #
8
11
  # AEMO::NMI acts as an object to simplify access to data and information
9
- # about a NMI and provide verification of the NMI value
12
+ # about a NMI and provide verification of the NMI value
13
+ #
14
+ # @author Joel Courtney
15
+ # @abstract Model for a National Metering Identifier.
16
+ # @since 2014-12-05
10
17
  class NMI
11
18
  # Operational Regions for the NMI
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
20
-
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
25
- NMI_ALLOCATIONS = {
26
- 'ACTEWP' => {
27
- title: 'Actew Distribution Ltd and Jemena Networks (ACT) Pty Ltd',
28
- friendly_title: 'ACTEWAgl',
29
- state: AEMO::Region.new('ACT'),
30
- type: 'electricity',
31
- includes: [/^(NGGG[A-HJ-NP-VX-Z\d][A-HJ-NP-Z\d]{5})$/,
32
- /^(7001\d{6})$/],
33
- excludes: []
34
- },
35
- 'CNRGYP' => {
36
- title: 'Essential Energy',
37
- friendly_title: 'Essential Energy',
38
- state: AEMO::Region.new('NSW'),
39
- type: 'electricity',
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: []
49
- },
50
- 'ENERGYAP' => {
51
- title: 'Ausgrid',
52
- friendly_title: 'Ausgrid',
53
- state: AEMO::Region.new('NSW'),
54
- type: 'electricity',
55
- includes: [/^(NCCC[A-HJ-NP-VX-Z\d][A-HJ-NP-Z\d]{5})$/,
56
- /^(410[234]\d{6})$/],
57
- excludes: []
58
- },
59
- 'INTEGP' => {
60
- title: 'Endeavour Energy',
61
- friendly_title: 'Endeavour Energy',
62
- state: AEMO::Region.new('NSW'),
63
- type: 'electricity',
64
- includes: [/^(NEEE[A-HJ-NP-VX-Z\d][A-HJ-NP-Z\d]{5})$/,
65
- /^(431\d{7})$/],
66
- excludes: []
67
- },
68
- 'TRANSGP' => {
69
- title: 'TransGrid',
70
- friendly_title: 'TransGrid',
71
- state: AEMO::Region.new('NSW'),
72
- type: 'electricity',
73
- includes: [/^(NTTT[A-HJ-NP-VX-Z\d][A-HJ-NP-Z\d]{5})$/,
74
- /^(460810[0-8]\d{3})$/],
75
- excludes: []
76
- },
77
- 'SNOWY' => {
78
- title: 'Snowy Hydro Ltd',
79
- friendly_title: 'Snowy Hydro',
80
- state: AEMO::Region.new('NSW'),
81
- type: 'electricity',
82
- includes: [/^(4708109\d{3})$/],
83
- excludes: []
84
- },
85
- 'NT_RESERVED' => {
86
- title: 'Northern Territory Reserved Block',
87
- friendly_title: 'Northern Territory Reserved Block',
88
- state: AEMO::Region.new('NT'),
89
- type: 'electricity',
90
- includes: [/^(250\d{7})$/],
91
- excludes: []
92
- },
93
- 'ERGONETP' => {
94
- title: 'Ergon Energy Corporation',
95
- friendly_title: 'Ergon Energy',
96
- state: AEMO::Region.new('QLD'),
97
- type: 'electricity',
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: []
106
- },
107
- 'ENERGEXP' => {
108
- title: 'ENERGEX Limited',
109
- friendly_title: 'Energex',
110
- state: AEMO::Region.new('QLD'),
111
- type: 'electricity',
112
- includes: [/^(QB\d{2}[A-HJ-NP-VX-Z\d][A-HJ-NP-Z\d]{5})$/,
113
- /^(31\d{8})$/],
114
- excludes: []
115
- },
116
- 'PLINKP' => {
117
- title: 'Qld Electricity Transmission Corp (Powerlink)',
118
- friendly_title: 'Powerlink',
119
- state: AEMO::Region.new('QLD'),
120
- type: 'electricity',
121
- includes: [/^(Q[A-HJ-NP-Z\d]{3}W[A-HJ-NP-Z\d]{5})$/,
122
- /^(320200\d{4})$/],
123
- excludes: []
124
- },
125
- 'UMPLP' => {
126
- title: 'SA Power Networks',
127
- friendly_title: 'SA Power Networks',
128
- state: AEMO::Region.new('SA'),
129
- type: 'electricity',
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: []
134
- },
135
- 'ETSATP' => {
136
- title: 'ElectraNet SA',
137
- friendly_title: 'ElectraNet SA',
138
- state: AEMO::Region.new('SA'),
139
- type: 'electricity',
140
- includes: [/^(S[A-HJ-NP-Z\d]{3}W[A-HJ-NP-Z\d]{5})$/,
141
- /^(210200\d{4})$/],
142
- excludes: []
143
- },
144
- 'AURORAP' => {
145
- title: 'TasNetworks',
146
- friendly_title: 'TasNetworks',
147
- state: AEMO::Region.new('TAS'),
148
- type: 'electricity',
149
- includes: [/^(T000000(([0-4]\d{3})|(500[01])))$/,
150
- /^(8000\d{6})$/,
151
- /^(8590[23]\d{5})$/],
152
- excludes: []
153
- },
154
- 'TRANSEND' => {
155
- title: 'TasNetworks',
156
- friendly_title: 'TasNetworks',
157
- state: AEMO::Region.new('TAS'),
158
- type: 'electricity',
159
- includes: [/^(T[A-HJ-NP-Z\d]{3}W[A-HJ-NP-Z\d]{5})$/],
160
- excludes: []
161
- },
162
- 'CITIPP' => {
163
- title: 'CitiPower',
164
- friendly_title: 'CitiPower',
165
- state: AEMO::Region.new('VIC'),
166
- type: 'electricity',
167
- includes: [/^(VAAA[A-HJ-NP-VX-Z\d][A-HJ-NP-Z\d]{5})$/,
168
- /^(610[23]\d{6})$/],
169
- excludes: []
170
- },
171
- 'EASTERN' => {
172
- title: 'SP AusNet',
173
- friendly_title: 'SP AusNet DNSP',
174
- state: AEMO::Region.new('VIC'),
175
- type: 'electricity',
176
- includes: [/^(VBBB[A-HJ-NP-VX-Z\d][A-HJ-NP-Z\d]{5})$/,
177
- /^(630[56]\d{6})$/],
178
- excludes: []
179
- },
180
- 'POWCP' => {
181
- title: 'PowerCor Australia',
182
- friendly_title: 'PowerCor',
183
- state: AEMO::Region.new('VIC'),
184
- type: 'electricity',
185
- includes: [/^(VCCC[A-HJ-NP-VX-Z\d][A-HJ-NP-Z\d]{5})$/,
186
- /^(620[34]\d{6})$/],
187
- excludes: []
188
- },
189
- 'SOLARISP' => {
190
- title: 'Jemena Electricity Networks (VIC)',
191
- friendly_title: 'Jemena',
192
- state: AEMO::Region.new('VIC'),
193
- type: 'electricity',
194
- includes: [/^(VDDD[A-HJ-NP-VX-Z\d][A-HJ-NP-Z\d]{5})$/,
195
- /^(6001\d{6})$/],
196
- excludes: []
197
- },
198
- 'UNITED' => {
199
- title: 'United Energy Distribution',
200
- friendly_title: 'United Energy',
201
- state: AEMO::Region.new('VIC'),
202
- type: 'electricity',
203
- includes: [/^(VEEE[A-HJ-NP-VX-Z\d][A-HJ-NP-Z\d]{5})$/,
204
- /^(640[78]\d{6})$/],
205
- excludes: []
206
- },
207
- 'GPUPP' => {
208
- title: 'SP AusNet TNSP',
209
- friendly_title: 'SP AusNet TNSP',
210
- state: AEMO::Region.new('VIC'),
211
- type: 'electricity',
212
- includes: [/^(V[A-HJ-NP-Z\d]{3}W[A-HJ-NP-Z\d]{5})$/,
213
- /^(650900\d{4})$/],
214
- excludes: []
215
- },
216
- 'WESTERNPOWER' => {
217
- title: 'Western Power',
218
- friendly_title: 'Western Power',
219
- state: AEMO::Region.new('WA'),
220
- type: 'electricity',
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: []
226
- },
227
- 'HORIZONPOWER' => {
228
- title: 'Horizon Power',
229
- friendly_title: 'Horizon Power',
230
- state: AEMO::Region.new('WA'),
231
- type: 'electricity',
232
- includes: [/^(8021\d{6})$/],
233
- excludes: []
234
- },
235
- 'GAS_NSW' => {
236
- title: 'GAS NSW',
237
- friendly_title: 'GAS NSW',
238
- state: AEMO::Region.new('NSW'),
239
- type: 'gas',
240
- includes: [/^(52\d{8})$/],
241
- excludes: []
242
- },
243
- 'GAS_VIC' => {
244
- title: 'GAS VIC',
245
- friendly_title: 'GAS VIC',
246
- state: AEMO::Region.new('VIC'),
247
- type: 'gas',
248
- includes: [/^(53\d{8})$/],
249
- excludes: []
250
- },
251
- 'GAS_QLD' => {
252
- title: 'GAS QLD',
253
- friendly_title: 'GAS QLD',
254
- state: AEMO::Region.new('QLD'),
255
- type: 'gas',
256
- includes: [/^(54\d{8})$/],
257
- excludes: []
258
- },
259
- 'GAS_SA' => {
260
- title: 'GAS SA',
261
- friendly_title: 'GAS SA',
262
- state: AEMO::Region.new('SA'),
263
- type: 'gas',
264
- includes: [/^(55\d{8})$/],
265
- excludes: []
266
- },
267
- 'GAS_WA' => {
268
- title: 'GAS WA',
269
- friendly_title: 'GAS WA',
270
- state: AEMO::Region.new('WA'),
271
- type: 'gas',
272
- includes: [/^(56\d{8})$/],
273
- excludes: []
274
- },
275
- 'GAS_TAS' => {
276
- title: 'GAS TAS',
277
- friendly_title: 'GAS TAS',
278
- state: AEMO::Region.new('TAS'),
279
- type: 'gas',
280
- includes: [/^(57\d{8})$/],
281
- excludes: []
282
- },
283
- 'FEDAIRPORTS' => {
284
- title: 'Federal Airports Corporation (Sydney Airport)',
285
- friendly_title: 'Sydney Airport',
286
- state: AEMO::Region.new('NSW'),
287
- type: 'electricity',
288
- includes: [/^(NJJJNR[A-HJ-NP-Z\d]{4})$/],
289
- excludes: []
290
- },
291
- 'EXEMPTNETWORKS' => {
292
- title: 'Exempt Networks - various',
293
- friendly_title: 'Exempt Networks - various',
294
- state: '',
295
- type: 'electricity',
296
- includes: [/^(NKKK[A-HJ-NP-VX-Z\d][A-HJ-NP-Z\d]{5})$/,
297
- /^(7102\d{6})$/],
298
- excludes: []
299
- },
300
- 'AEMORESERVED' => {
301
- title: 'AEMO Reserved',
302
- friendly_title: 'AEMO Reserved',
303
- state: '',
304
- type: 'electricity',
305
- includes: [/^(880[1-5]\d{6})$/,
306
- /^(9\d{9})$/],
307
- excludes: []
308
- }
19
+ REGIONS = {
20
+ 'ACT' => 'Australian Capital Territory',
21
+ 'NSW' => 'New South Wales',
22
+ 'QLD' => 'Queensland',
23
+ 'SA' => 'South Australia',
24
+ 'TAS' => 'Tasmania',
25
+ 'VIC' => 'Victoria',
26
+ 'WA' => 'Western Australia',
27
+ 'NT' => 'Northern Territory'
309
28
  }.freeze
29
+
310
30
  # Transmission Node Identifier Codes are loaded from a json file
311
31
  # Obtained from http://www.nemweb.com.au/
312
32
  #
313
33
  # See /lib/data for further data manipulation required
314
- TNI_CODES = JSON.parse(File.read(File.join(File.dirname(__FILE__), '..',
315
- 'data', 'aemo-tni.json'))).freeze
34
+ TNI_CODES = JSON.parse(
35
+ File.read(
36
+ File.join(File.dirname(__FILE__), '..', 'data', 'aemo-tni.json')
37
+ )
38
+ ).freeze
39
+
316
40
  # Distribution Loss Factor Codes are loaded from a json file
317
41
  # Obtained from MSATS, matching to DNSP from file
318
42
  # https://www.aemo.com.au/-/media/Files/Electricity/NEM/
@@ -321,8 +45,11 @@ module AEMO
321
45
  #
322
46
  # Last accessed 2017-08-01
323
47
  # See /lib/data for further data manipulation required
324
- DLF_CODES = JSON.parse(File.read(File.join(File.dirname(__FILE__), '..',
325
- 'data', 'aemo-dlf.json'))).freeze
48
+ DLF_CODES = JSON.parse(
49
+ File.read(
50
+ File.join(File.dirname(__FILE__), '..', 'data', 'aemo-dlf.json')
51
+ )
52
+ ).freeze
326
53
 
327
54
  # [String] National Meter Identifier
328
55
  @nmi = nil
@@ -344,6 +71,38 @@ module AEMO
344
71
  :jurisdiction_code, :classification_code, :status, :address,
345
72
  :meters, :roles, :data_streams
346
73
 
74
+ class << self
75
+ # A function to validate the NMI provided
76
+ #
77
+ # @param [String] nmi the nmi to be checked
78
+ # @return [Boolean] whether or not the nmi is valid
79
+ def valid_nmi?(nmi)
80
+ ((nmi.length == 10) && !nmi.match(/^([A-HJ-NP-Z\d]{10})/).nil?)
81
+ end
82
+
83
+ # A function to calculate the checksum value for a given National Meter
84
+ # Identifier
85
+ #
86
+ # @param [String] nmi the NMI to check the checksum against
87
+ # @param [Integer] checksum_value the checksum value to check against the
88
+ # current National Meter Identifier's checksum value
89
+ # @return [Boolean] whether or not the checksum is valid
90
+ def valid_checksum?(nmi, checksum_value)
91
+ nmi = AEMO::NMI.new(nmi)
92
+ nmi.valid_checksum?(checksum_value)
93
+ end
94
+
95
+ # Find the Network for a given NMI
96
+ #
97
+ # @param [String] nmi NMI
98
+ # @returns [AEMO::NMI::Allocation] The Network information
99
+ def network(nmi)
100
+ AEMO::NMI::Allocation.find_by_nmi(nmi)
101
+ end
102
+
103
+ alias allocation network
104
+ end
105
+
347
106
  # Initialize a NMI file
348
107
  #
349
108
  # @param [String] nmi the National Meter Identifier (NMI)
@@ -354,9 +113,7 @@ module AEMO
354
113
  def initialize(nmi, options = {})
355
114
  raise ArgumentError, 'NMI is not a string' unless nmi.is_a?(String)
356
115
  raise ArgumentError, 'NMI is not 10 characters' unless nmi.length == 10
357
- unless AEMO::NMI.valid_nmi?(nmi)
358
- raise ArgumentError, 'NMI is not constructed with valid characters'
359
- end
116
+ raise ArgumentError, 'NMI is not constructed with valid characters' unless AEMO::NMI.valid_nmi?(nmi)
360
117
 
361
118
  @nmi = nmi
362
119
  @meters = []
@@ -381,6 +138,8 @@ module AEMO
381
138
  AEMO::NMI.network(@nmi)
382
139
  end
383
140
 
141
+ alias allocation network
142
+
384
143
  # A function to calculate the checksum value for a given
385
144
  # National Meter Identifier
386
145
  #
@@ -412,9 +171,7 @@ module AEMO
412
171
  #
413
172
  # @return [Hash] MSATS NMI Detail data
414
173
  def raw_msats_nmi_detail(options = {})
415
- unless AEMO::MSATS.can_authenticate?
416
- raise ArgumentError, 'MSATS has no authentication credentials'
417
- end
174
+ raise ArgumentError, 'MSATS has no authentication credentials' unless AEMO::MSATS.can_authenticate?
418
175
  AEMO::MSATS.nmi_detail(@nmi, options)
419
176
  end
420
177
 
@@ -530,54 +287,18 @@ module AEMO
530
287
 
531
288
  # The current annual load in MWh
532
289
  #
290
+ # @todo Use TimeDifference for more accurate annualised load
533
291
  # @return [Integer] the current annual load for the meter in MWh
534
292
  def current_annual_load
535
293
  (current_daily_load * 365.2425 / 1000).to_i
536
294
  end
537
295
 
538
- # A function to validate the NMI provided
539
- #
540
- # @param [String] nmi the nmi to be checked
541
- # @return [Boolean] whether or not the nmi is valid
542
- def self.valid_nmi?(nmi)
543
- ((nmi.length == 10) && !nmi.match(/^([A-HJ-NP-Z\d]{10})/).nil?)
544
- end
545
-
546
- # A function to calculate the checksum value for a given National Meter
547
- # Identifier
548
- #
549
- # @param [String] nmi the NMI to check the checksum against
550
- # @param [Integer] checksum_value the checksum value to check against the
551
- # current National Meter Identifier's checksum value
552
- # @return [Boolean] whether or not the checksum is valid
553
- def self.valid_checksum?(nmi, checksum_value)
554
- nmi = AEMO::NMI.new(nmi)
555
- nmi.valid_checksum?(checksum_value)
556
- end
557
-
558
- # Find the Network for a given NMI
559
- #
560
- # @param [String] nmi NMI
561
- # @returns [Hash] The Network information
562
- def self.network(nmi)
563
- network = nil
564
- AEMO::NMI::NMI_ALLOCATIONS.each_pair do |identifier, details|
565
- details[:includes].each do |pattern|
566
- if nmi.match(pattern)
567
- network = { identifier => details }
568
- break
569
- end
570
- end
571
- end
572
- network
573
- end
574
-
575
296
  # A function to return the distribution loss factor value for a given date
576
297
  #
577
298
  # @param [DateTime, Time] datetime the date for the distribution loss factor
578
299
  # value
579
300
  # @return [nil, float] the distribution loss factor value
580
- def dlfc_value(datetime = DateTime.now)
301
+ def dlfc_value(datetime = Time.now)
581
302
  if @dlf.nil?
582
303
  raise 'No DLF set, ensure that you have set the value either via the' \
583
304
  'update_from_msats! function or manually'
@@ -585,8 +306,8 @@ module AEMO
585
306
  raise 'DLF is invalid' unless DLF_CODES.keys.include?(@dlf)
586
307
  raise 'Invalid date' unless [DateTime, Time].include?(datetime.class)
587
308
  possible_values = DLF_CODES[@dlf].select do |x|
588
- DateTime.parse(x['FromDate']) <= datetime &&
589
- DateTime.parse(x['ToDate']) >= datetime
309
+ Time.parse(x['FromDate']) <= datetime &&
310
+ Time.parse(x['ToDate']) >= datetime
590
311
  end
591
312
  if possible_values.empty?
592
313
  nil
@@ -600,13 +321,16 @@ module AEMO
600
321
  # @param [DateTime, Time] start the date for the distribution loss factor value
601
322
  # @param [DateTime, Time] finish the date for the distribution loss factor value
602
323
  # @return [Array(Hash)] array of hashes of start, finish and value
603
- def dlfc_values(start = DateTime.now, finish = DateTime.now)
604
- raise 'No DLF set, ensure that you have set the value either via the update_from_msats! function or manually' if @dlf.nil?
324
+ def dlfc_values(start = Time.now, finish = Time.now)
325
+ if @dlf.nil?
326
+ raise 'No DLF set, ensure that you have set the value either via the '\
327
+ 'update_from_msats! function or manually'
328
+ end
605
329
  raise 'DLF is invalid' unless DLF_CODES.keys.include?(@dlf)
606
330
  raise 'Invalid start' unless [DateTime, Time].include?(start.class)
607
331
  raise 'Invalid finish' unless [DateTime, Time].include?(finish.class)
608
332
  raise 'start cannot be after finish' if start > finish
609
- DLF_CODES[@dlf].reject { |x| start > DateTime.parse(x['ToDate']) || finish < DateTime.parse(x['FromDate']) }
333
+ DLF_CODES[@dlf].reject { |x| start > Time.parse(x['ToDate']) || finish < Time.parse(x['FromDate']) }
610
334
  .map { |x| { 'start' => x['FromDate'], 'finish' => x['ToDate'], 'value' => x['Value'].to_f } }
611
335
  end
612
336
 
@@ -614,13 +338,16 @@ module AEMO
614
338
  #
615
339
  # @param [DateTime, Time] datetime the date for the distribution loss factor value
616
340
  # @return [nil, float] the transmission node identifier loss factor value
617
- def tni_value(datetime = DateTime.now)
618
- raise 'No TNI set, ensure that you have set the value either via the update_from_msats! function or manually' if @tni.nil?
341
+ def tni_value(datetime = Time.now)
342
+ if @tni.nil?
343
+ raise 'No TNI set, ensure that you have set the value either via the '\
344
+ 'update_from_msats! function or manually'
345
+ end
619
346
  raise 'TNI is invalid' unless TNI_CODES.keys.include?(@tni)
620
347
  raise 'Invalid date' unless [DateTime, Time].include?(datetime.class)
621
- possible_values = TNI_CODES[@tni].select { |x| DateTime.parse(x['FromDate']) <= datetime && datetime <= DateTime.parse(x['ToDate']) }
348
+ possible_values = TNI_CODES[@tni].select { |x| Time.parse(x['FromDate']) <= datetime && datetime <= Time.parse(x['ToDate']) }
622
349
  return nil if possible_values.empty?
623
- possible_values = possible_values.first['mlf_data']['loss_factors'].select { |x| DateTime.parse(x['start']) <= datetime && datetime <= DateTime.parse(x['finish']) }
350
+ possible_values = possible_values.first['mlf_data']['loss_factors'].select { |x| Time.parse(x['start']) <= datetime && datetime <= Time.parse(x['finish']) }
624
351
  return nil if possible_values.empty?
625
352
  possible_values.first['value'].to_f
626
353
  end
@@ -630,14 +357,21 @@ module AEMO
630
357
  # @param [DateTime, Time] start the date for the distribution loss factor value
631
358
  # @param [DateTime, Time] finish the date for the distribution loss factor value
632
359
  # @return [Array(Hash)] array of hashes of start, finish and value
633
- def tni_values(start = DateTime.now, finish = DateTime.now)
634
- raise 'No TNI set, ensure that you have set the value either via the update_from_msats! function or manually' if @tni.nil?
360
+ def tni_values(start = Time.now, finish = Time.now)
361
+ if @tni.nil?
362
+ raise 'No TNI set, ensure that you have set the value either via the '\
363
+ 'update_from_msats! function or manually'
364
+ end
635
365
  raise 'TNI is invalid' unless TNI_CODES.keys.include?(@tni)
636
366
  raise 'Invalid start' unless [DateTime, Time].include?(start.class)
637
367
  raise 'Invalid finish' unless [DateTime, Time].include?(finish.class)
638
368
  raise 'start cannot be after finish' if start > finish
639
- possible_values = TNI_CODES[@tni]
640
- .reject { |x| start > DateTime.parse(x['ToDate']) || finish < DateTime.parse(x['FromDate']) }
369
+
370
+ possible_values = TNI_CODES[@tni].reject do |tni_code|
371
+ start > Time.parse(tni_code['ToDate']) ||
372
+ finish < Time.parse(tni_code['FromDate'])
373
+ end
374
+
641
375
  return nil if possible_values.empty?
642
376
  possible_values.map { |x| x['mlf_data']['loss_factors'] }
643
377
  end
data/lib/aemo/version.rb CHANGED
@@ -24,7 +24,7 @@
24
24
  # @author Joel Courtney <euphemize@gmail.com>
25
25
  module AEMO
26
26
  # aemo version
27
- VERSION = '0.2.1'.freeze
27
+ VERSION = '0.3.0-rc1'
28
28
 
29
29
  # aemo version split amongst different revisions
30
30
  MAJOR_VERSION, MINOR_VERSION, REVISION = VERSION.split('.').map(&:to_i)
data/lib/aemo.rb CHANGED
@@ -11,9 +11,11 @@ require 'aemo/market/node.rb'
11
11
  require 'aemo/meter.rb'
12
12
  require 'aemo/nem12.rb'
13
13
  require 'aemo/nmi.rb'
14
+ require 'aemo/nmi/allocation.rb'
14
15
  require 'aemo/msats.rb'
15
16
  require 'aemo/register.rb'
16
17
  require 'aemo/version.rb'
18
+ require 'aemo/exceptions/invalid_nmi_allocation_type.rb'
17
19
 
18
20
  # AEMO Module to encapsulate all AEMO classes
19
21
  module AEMO
@@ -24,8 +24,8 @@ CSV.parse(file_contents, headers: true, converters: :numeric).each do |row|
24
24
  row.headers.select { |x| x =~ /^FY\d{2}$/ }.sort.reverse.each do |fin_year|
25
25
  year = "20#{fin_year.match(/FY(\d{2})/)[1]}".to_i
26
26
  @mlf_data[row['TNI']][:loss_factors] << {
27
- start: DateTime.parse("#{year - 1}-07-01T00:00:00+1000"),
28
- finish: DateTime.parse("#{year}-07-01T00:00:00+1000"),
27
+ start: Time.parse("#{year - 1}-07-01T00:00:00+1000"),
28
+ finish: Time.parse("#{year}-07-01T00:00:00+1000"),
29
29
  value: row[fin_year]
30
30
  }
31
31
  end
@@ -62,8 +62,8 @@ end
62
62
  unless @mlf_data[code].nil?
63
63
  output_data_instance[:mlf_data] = @mlf_data[code].deep_dup
64
64
  output_data_instance[:mlf_data][:loss_factors].reject! do |x|
65
- DateTime.parse(output_data_instance['ToDate']) < x[:start] ||
66
- DateTime.parse(output_data_instance['FromDate']) >= x[:finish]
65
+ Time.parse(output_data_instance['ToDate']) < x[:start] ||
66
+ Time.parse(output_data_instance['FromDate']) >= x[:finish]
67
67
  end
68
68
  puts 'output_data_instance[:mlf_data][:loss_factors]: ' \
69
69
  "#{output_data_instance[:mlf_data][:loss_factors].inspect}"
@@ -16,14 +16,14 @@ describe AEMO::Market::Interval do
16
16
  expect { AEMO::Market::Interval.new('2016-03-01T00:30:00', 'REGION' => 'NSW', 'TOTALDEMAND' => 1000.23, 'RRP' => 76.54, 'PERIODTYPE' => 'TRADING') }.not_to raise_error
17
17
  end
18
18
  it 'has a trailing datetime' do
19
- expect(@interval.datetime).to eq(DateTime.parse('2016-03-01T00:30:00+1000'))
19
+ expect(@interval.datetime).to eq(Time.parse('2016-03-01T00:30:00+1000'))
20
20
  end
21
21
  it 'has a leading datetime' do
22
- expect(@interval.datetime(false)).to eq(DateTime.parse('2016-03-01T00:00:00+1000'))
22
+ expect(@interval.datetime(false)).to eq(Time.parse('2016-03-01T00:00:00+1000'))
23
23
  end
24
24
  it 'has a leading datetime for dispatch' do
25
25
  @interval = AEMO::Market::Interval.new('2016-03-01T00:30:00', 'REGION' => 'NSW', 'TOTALDEMAND' => 1000.23, 'RRP' => 76.54, 'PERIODTYPE' => '')
26
- expect(@interval.datetime(false)).to eq(DateTime.parse('2016-03-01T00:25:00+1000'))
26
+ expect(@interval.datetime(false)).to eq(Time.parse('2016-03-01T00:25:00+1000'))
27
27
  end
28
28
  it 'has an interval length' do
29
29
  expect(@interval.interval_length).to eq(Time.at(300))
@@ -48,15 +48,11 @@ describe AEMO::MSATS do
48
48
  end
49
49
 
50
50
  it 'should return a hash of information' do
51
- expect(AEMO::MSATS.c4('4001234567', DateTime.now, DateTime.now, DateTime.now)).to be_a(Hash)
51
+ expect(AEMO::MSATS.c4('4001234567', Time.now, Time.now, Time.now)).to be_a(Hash)
52
52
  end
53
53
  it 'should raise an error for a bad nmi' do
54
54
  expect { AEMO::MSATS.c4('BOBISAFISH') }.to raise_error(ArgumentError)
55
55
  end
56
- it 'should return a hash of information' do
57
- # AEMO::MSATS.c4('4001234566', DateTime.now, DateTime.now, DateTime.now)
58
- # TODO workout what the different errors are here...
59
- end
60
56
  end
61
57
 
62
58
  describe 'invalid MSATS account' do
@@ -67,9 +63,9 @@ describe AEMO::MSATS do
67
63
  it 'should return response' do
68
64
  expect(AEMO::MSATS.c4(
69
65
  '4001234567',
70
- DateTime.now,
71
- DateTime.now,
72
- DateTime.now
66
+ Time.now,
67
+ Time.now,
68
+ Time.now
73
69
  ).class).to eq(HTTParty::Response)
74
70
  end
75
71
  end