aemo 0.5.0 → 0.6.0
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/dispatchable.rb +2 -2
- data/lib/aemo/exceptions/invalid_nmi_allocation_type.rb +1 -1
- data/lib/aemo/exceptions/time_error.rb +20 -0
- data/lib/aemo/market/interval.rb +4 -4
- data/lib/aemo/market/node.rb +9 -3
- data/lib/aemo/market.rb +2 -4
- data/lib/aemo/msats.rb +70 -54
- data/lib/aemo/nem12/data_stream_suffix.rb +1 -1
- data/lib/aemo/nem12/quality_method.rb +14 -10
- data/lib/aemo/nem12/unit_of_measurement.rb +42 -42
- data/lib/aemo/nem12.rb +300 -94
- data/lib/aemo/nem13.rb +1 -2
- data/lib/aemo/nmi/allocation.rb +6 -7
- data/lib/aemo/nmi.rb +48 -38
- data/lib/aemo/region.rb +4 -3
- data/lib/aemo/register.rb +7 -7
- data/lib/aemo/struct.rb +3 -0
- data/lib/aemo/time.rb +112 -0
- data/lib/aemo/version.rb +1 -2
- data/lib/aemo.rb +13 -11
- data/lib/data/xml_to_json.rb +2 -4
- data/spec/aemo_spec.rb +0 -7
- data/spec/lib/aemo/market/interval_spec.rb +30 -12
- data/spec/lib/aemo/market/node_spec.rb +11 -9
- data/spec/lib/aemo/market_spec.rb +5 -4
- data/spec/lib/aemo/meter_spec.rb +2 -2
- data/spec/lib/aemo/msats_spec.rb +68 -56
- data/spec/lib/aemo/nem12_spec.rb +154 -43
- data/spec/lib/aemo/nmi/allocation_spec.rb +23 -18
- data/spec/lib/aemo/nmi_spec.rb +98 -72
- data/spec/lib/aemo/region_spec.rb +23 -18
- data/spec/spec_helper.rb +13 -13
- metadata +21 -443
data/lib/aemo/nmi.rb
CHANGED
@@ -5,7 +5,7 @@ require 'json'
|
|
5
5
|
require 'time'
|
6
6
|
require 'ostruct'
|
7
7
|
|
8
|
-
require 'aemo/nmi/allocation
|
8
|
+
require 'aemo/nmi/allocation'
|
9
9
|
|
10
10
|
module AEMO
|
11
11
|
# [AEMO::NMI]
|
@@ -22,11 +22,11 @@ module AEMO
|
|
22
22
|
'ACT' => 'Australian Capital Territory',
|
23
23
|
'NSW' => 'New South Wales',
|
24
24
|
'QLD' => 'Queensland',
|
25
|
-
'SA'
|
25
|
+
'SA' => 'South Australia',
|
26
26
|
'TAS' => 'Tasmania',
|
27
27
|
'VIC' => 'Victoria',
|
28
|
-
'WA'
|
29
|
-
'NT'
|
28
|
+
'WA' => 'Western Australia',
|
29
|
+
'NT' => 'Northern Territory'
|
30
30
|
}.freeze
|
31
31
|
|
32
32
|
# Transmission Node Identifier Codes are loaded from a json file
|
@@ -79,7 +79,7 @@ module AEMO
|
|
79
79
|
# @param [String] nmi the nmi to be checked
|
80
80
|
# @return [Boolean] whether or not the nmi is valid
|
81
81
|
def valid_nmi?(nmi)
|
82
|
-
(
|
82
|
+
(nmi.length == 10) && !nmi.match(/^([A-HJ-NP-Z\d]{10})/).nil?
|
83
83
|
end
|
84
84
|
|
85
85
|
# A function to calculate the checksum value for a given National Meter
|
@@ -159,14 +159,13 @@ module AEMO
|
|
159
159
|
# Identifier
|
160
160
|
def checksum
|
161
161
|
summation = 0
|
162
|
-
@nmi.reverse.
|
162
|
+
@nmi.reverse.chars.each_index do |i|
|
163
163
|
value = nmi[nmi.length - i - 1].ord
|
164
164
|
value *= 2 if i.even?
|
165
|
-
value = value.to_s.
|
165
|
+
value = value.to_s.chars.map(&:to_i).reduce(:+)
|
166
166
|
summation += value
|
167
167
|
end
|
168
|
-
|
169
|
-
checksum
|
168
|
+
(10 - (summation % 10)) % 10
|
170
169
|
end
|
171
170
|
|
172
171
|
# Provided MSATS is configured, gets the MSATS data for the NMI
|
@@ -174,6 +173,7 @@ module AEMO
|
|
174
173
|
# @return [Hash] MSATS NMI Detail data
|
175
174
|
def raw_msats_nmi_detail(options = {})
|
176
175
|
raise ArgumentError, 'MSATS has no authentication credentials' unless AEMO::MSATS.can_authenticate?
|
176
|
+
|
177
177
|
AEMO::MSATS.nmi_detail(@nmi, options)
|
178
178
|
end
|
179
179
|
|
@@ -233,7 +233,7 @@ module AEMO
|
|
233
233
|
data_streams = @msats_detail['DataStreams']['DataStream']
|
234
234
|
data_streams = [data_streams] if data_streams.is_a?(Hash) # Deal with issue of only one existing
|
235
235
|
data_streams.each do |stream|
|
236
|
-
@data_streams <<
|
236
|
+
@data_streams << Struct::DataStream.new(
|
237
237
|
suffix: stream['Suffix'],
|
238
238
|
profile_name: stream['ProfileName'],
|
239
239
|
averaged_daily_load: stream['AveragedDailyLoad'],
|
@@ -270,10 +270,10 @@ module AEMO
|
|
270
270
|
@meters.select { |x| x.status == status.to_s }
|
271
271
|
end
|
272
272
|
|
273
|
-
# Returns the data_stream
|
273
|
+
# Returns the data_stream Structs for the requested status (A/I)
|
274
274
|
#
|
275
275
|
# @param [String] status the stateus [A|I]
|
276
|
-
# @return [Array<
|
276
|
+
# @return [Array<Struct>] Returns an array of Structs for the
|
277
277
|
# current Meters
|
278
278
|
def data_streams_by_status(status = 'A')
|
279
279
|
@data_streams.select { |x| x.status == status.to_s }
|
@@ -297,19 +297,20 @@ module AEMO
|
|
297
297
|
|
298
298
|
# A function to return the distribution loss factor value for a given date
|
299
299
|
#
|
300
|
-
# @param [DateTime, Time] datetime the date for the distribution loss factor
|
300
|
+
# @param [DateTime, ::Time] datetime the date for the distribution loss factor
|
301
301
|
# value
|
302
302
|
# @return [nil, float] the distribution loss factor value
|
303
|
-
def dlfc_value(datetime = Time.now)
|
303
|
+
def dlfc_value(datetime = ::Time.now)
|
304
304
|
if @dlf.nil?
|
305
305
|
raise 'No DLF set, ensure that you have set the value either via the' \
|
306
306
|
'update_from_msats! function or manually'
|
307
307
|
end
|
308
308
|
raise 'DLF is invalid' unless DLF_CODES.keys.include?(@dlf)
|
309
|
-
raise 'Invalid date' unless [DateTime, Time].include?(datetime.class)
|
309
|
+
raise 'Invalid date' unless [DateTime, ::Time].include?(datetime.class)
|
310
|
+
|
310
311
|
possible_values = DLF_CODES[@dlf].select do |x|
|
311
|
-
Time.parse(x['FromDate']) <= datetime &&
|
312
|
-
Time.parse(x['ToDate']) >= datetime
|
312
|
+
::Time.parse(x['FromDate']) <= datetime &&
|
313
|
+
::Time.parse(x['ToDate']) >= datetime
|
313
314
|
end
|
314
315
|
if possible_values.empty?
|
315
316
|
nil
|
@@ -320,61 +321,70 @@ module AEMO
|
|
320
321
|
|
321
322
|
# A function to return the distribution loss factor value for a given date
|
322
323
|
#
|
323
|
-
# @param [DateTime, Time] start the date for the distribution loss factor value
|
324
|
-
# @param [DateTime, Time] finish the date for the distribution loss factor value
|
324
|
+
# @param [DateTime, ::Time] start the date for the distribution loss factor value
|
325
|
+
# @param [DateTime, ::Time] finish the date for the distribution loss factor value
|
325
326
|
# @return [Array(Hash)] array of hashes of start, finish and value
|
326
|
-
def dlfc_values(start = Time.now, finish = Time.now)
|
327
|
+
def dlfc_values(start = ::Time.now, finish = ::Time.now)
|
327
328
|
if @dlf.nil?
|
328
|
-
raise 'No DLF set, ensure that you have set the value either via the '\
|
329
|
+
raise 'No DLF set, ensure that you have set the value either via the ' \
|
329
330
|
'update_from_msats! function or manually'
|
330
331
|
end
|
331
332
|
raise 'DLF is invalid' unless DLF_CODES.keys.include?(@dlf)
|
332
|
-
raise 'Invalid start' unless [DateTime, Time].include?(start.class)
|
333
|
-
raise 'Invalid finish' unless [DateTime, Time].include?(finish.class)
|
333
|
+
raise 'Invalid start' unless [DateTime, ::Time].include?(start.class)
|
334
|
+
raise 'Invalid finish' unless [DateTime, ::Time].include?(finish.class)
|
334
335
|
raise 'start cannot be after finish' if start > finish
|
335
|
-
|
336
|
+
|
337
|
+
DLF_CODES[@dlf].reject { |x| start > ::Time.parse(x['ToDate']) || finish < ::Time.parse(x['FromDate']) }
|
336
338
|
.map { |x| { 'start' => x['FromDate'], 'finish' => x['ToDate'], 'value' => x['Value'].to_f } }
|
337
339
|
end
|
338
340
|
|
339
341
|
# A function to return the transmission node identifier loss factor value for a given date
|
340
342
|
#
|
341
|
-
# @param [DateTime, Time] datetime the date for the distribution loss factor value
|
343
|
+
# @param [DateTime, ::Time] datetime the date for the distribution loss factor value
|
342
344
|
# @return [nil, float] the transmission node identifier loss factor value
|
343
|
-
def tni_value(datetime = Time.now)
|
345
|
+
def tni_value(datetime = ::Time.now)
|
344
346
|
if @tni.nil?
|
345
|
-
raise 'No TNI set, ensure that you have set the value either via the '\
|
347
|
+
raise 'No TNI set, ensure that you have set the value either via the ' \
|
346
348
|
'update_from_msats! function or manually'
|
347
349
|
end
|
348
350
|
raise 'TNI is invalid' unless TNI_CODES.keys.include?(@tni)
|
349
|
-
raise 'Invalid date' unless [DateTime, Time].include?(datetime.class)
|
350
|
-
|
351
|
+
raise 'Invalid date' unless [DateTime, ::Time].include?(datetime.class)
|
352
|
+
|
353
|
+
possible_values = TNI_CODES[@tni].select do |x|
|
354
|
+
::Time.parse(x['FromDate']) <= datetime && datetime <= ::Time.parse(x['ToDate'])
|
355
|
+
end
|
351
356
|
return nil if possible_values.empty?
|
352
|
-
|
357
|
+
|
358
|
+
possible_values = possible_values.first['mlf_data']['loss_factors'].select do |x|
|
359
|
+
::Time.parse(x['start']) <= datetime && datetime <= ::Time.parse(x['finish'])
|
360
|
+
end
|
353
361
|
return nil if possible_values.empty?
|
362
|
+
|
354
363
|
possible_values.first['value'].to_f
|
355
364
|
end
|
356
365
|
|
357
366
|
# A function to return the transmission node identifier loss factor value for a given date
|
358
367
|
#
|
359
|
-
# @param [DateTime, Time] start the date for the distribution loss factor value
|
360
|
-
# @param [DateTime, Time] finish the date for the distribution loss factor value
|
368
|
+
# @param [DateTime, ::Time] start the date for the distribution loss factor value
|
369
|
+
# @param [DateTime, ::Time] finish the date for the distribution loss factor value
|
361
370
|
# @return [Array(Hash)] array of hashes of start, finish and value
|
362
|
-
def tni_values(start = Time.now, finish = Time.now)
|
371
|
+
def tni_values(start = ::Time.now, finish = ::Time.now)
|
363
372
|
if @tni.nil?
|
364
|
-
raise 'No TNI set, ensure that you have set the value either via the '\
|
373
|
+
raise 'No TNI set, ensure that you have set the value either via the ' \
|
365
374
|
'update_from_msats! function or manually'
|
366
375
|
end
|
367
376
|
raise 'TNI is invalid' unless TNI_CODES.keys.include?(@tni)
|
368
|
-
raise 'Invalid start' unless [DateTime, Time].include?(start.class)
|
369
|
-
raise 'Invalid finish' unless [DateTime, Time].include?(finish.class)
|
377
|
+
raise 'Invalid start' unless [DateTime, ::Time].include?(start.class)
|
378
|
+
raise 'Invalid finish' unless [DateTime, ::Time].include?(finish.class)
|
370
379
|
raise 'start cannot be after finish' if start > finish
|
371
380
|
|
372
381
|
possible_values = TNI_CODES[@tni].reject do |tni_code|
|
373
|
-
start > Time.parse(tni_code['ToDate']) ||
|
374
|
-
finish < Time.parse(tni_code['FromDate'])
|
382
|
+
start > ::Time.parse(tni_code['ToDate']) ||
|
383
|
+
finish < ::Time.parse(tni_code['FromDate'])
|
375
384
|
end
|
376
385
|
|
377
386
|
return nil if possible_values.empty?
|
387
|
+
|
378
388
|
possible_values.map { |x| x['mlf_data']['loss_factors'] }
|
379
389
|
end
|
380
390
|
end
|
data/lib/aemo/region.rb
CHANGED
@@ -12,11 +12,11 @@ module AEMO
|
|
12
12
|
'ACT' => 'Australian Capital Territory',
|
13
13
|
'NSW' => 'New South Wales',
|
14
14
|
'QLD' => 'Queensland',
|
15
|
-
'SA'
|
15
|
+
'SA' => 'South Australia',
|
16
16
|
'TAS' => 'Tasmania',
|
17
17
|
'VIC' => 'Victoria',
|
18
|
-
'NT'
|
19
|
-
'WA'
|
18
|
+
'NT' => 'Northern Territory',
|
19
|
+
'WA' => 'Western Australia'
|
20
20
|
}.freeze
|
21
21
|
|
22
22
|
attr_accessor :region
|
@@ -34,6 +34,7 @@ module AEMO
|
|
34
34
|
# @return [self]
|
35
35
|
def initialize(region)
|
36
36
|
raise ArgumentError, "Region '#{region}' is not valid." unless valid_region?(region)
|
37
|
+
|
37
38
|
@region = region.upcase
|
38
39
|
@full_name = REGIONS[@region]
|
39
40
|
@current_trading = []
|
data/lib/aemo/register.rb
CHANGED
@@ -28,14 +28,14 @@ module AEMO
|
|
28
28
|
# @return [AEMO::Register] description of returned object
|
29
29
|
def self.from_hash(register)
|
30
30
|
AEMO::Register.new(
|
31
|
-
controlled_load:
|
32
|
-
dial_format:
|
33
|
-
multiplier:
|
31
|
+
controlled_load: register['ControlledLoad'] == 'Y',
|
32
|
+
dial_format: register['DialFormat'],
|
33
|
+
multiplier: register['Multiplier'],
|
34
34
|
network_tariff_code: register['NetworkTariffCode'],
|
35
|
-
register_id:
|
36
|
-
status:
|
37
|
-
time_of_day:
|
38
|
-
unit_of_measure:
|
35
|
+
register_id: register['RegisterID'],
|
36
|
+
status: register['Status'],
|
37
|
+
time_of_day: register['TimeOfDay'],
|
38
|
+
unit_of_measure: register['UnitOfMeasure']
|
39
39
|
)
|
40
40
|
end
|
41
41
|
end
|
data/lib/aemo/struct.rb
ADDED
data/lib/aemo/time.rb
ADDED
@@ -0,0 +1,112 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'time'
|
4
|
+
require 'active_support/all'
|
5
|
+
|
6
|
+
require_relative 'exceptions/time_error'
|
7
|
+
|
8
|
+
module AEMO
|
9
|
+
# [AEMO::Time] provides time helpers for AEMO services.
|
10
|
+
module Time
|
11
|
+
NEMTIMEZONE = 'Australia/Brisbane'
|
12
|
+
TIMESTAMP14 = '%Y%m%d%H%M%S'
|
13
|
+
TIMESTAMP14_PATTERN = /^\d{4}\d{2}\d{2}\d{2}\d{2}\d{2}$/
|
14
|
+
TIMESTAMP12 = '%Y%m%d%H%M'
|
15
|
+
TIMESTAMP12_PATTERN = /^\d{4}\d{2}\d{2}\d{2}\d{2}$/
|
16
|
+
TIMESTAMP8 = '%Y%m%d'
|
17
|
+
TIMESTAMP8_PATTERN = /^\d{4}\d{2}\d{2}$/
|
18
|
+
|
19
|
+
class << self
|
20
|
+
# Format a time to a timestamp 14.
|
21
|
+
#
|
22
|
+
# @param [Time] time
|
23
|
+
# @return [String]
|
24
|
+
def format_timestamp14(time)
|
25
|
+
time.in_time_zone(NEMTIMEZONE).strftime(TIMESTAMP14)
|
26
|
+
end
|
27
|
+
|
28
|
+
# Format a time to a timestamp 12.
|
29
|
+
#
|
30
|
+
# @param [Time] time
|
31
|
+
# @return [String]
|
32
|
+
def format_timestamp12(time)
|
33
|
+
time.in_time_zone(NEMTIMEZONE).strftime(TIMESTAMP12)
|
34
|
+
end
|
35
|
+
|
36
|
+
# Format a time to a timestamp 8.
|
37
|
+
#
|
38
|
+
# @param [Time] time
|
39
|
+
# @return [String]
|
40
|
+
def format_timestamp8(time)
|
41
|
+
time.in_time_zone(NEMTIMEZONE).strftime(TIMESTAMP8)
|
42
|
+
end
|
43
|
+
|
44
|
+
# Parse a 14 character timestamp.
|
45
|
+
#
|
46
|
+
# @param [String] string
|
47
|
+
# @raise [AEMO::TimeError]
|
48
|
+
# @return [Time]
|
49
|
+
def parse_timestamp14(string)
|
50
|
+
raise AEMO::TimeError unless string.match(TIMESTAMP14_PATTERN)
|
51
|
+
|
52
|
+
::Time.find_zone(NEMTIMEZONE).strptime(string, TIMESTAMP14)
|
53
|
+
end
|
54
|
+
|
55
|
+
# Parse a 12 character timestamp.
|
56
|
+
#
|
57
|
+
# @param [String] string
|
58
|
+
# @return [Time]
|
59
|
+
def parse_timestamp12(string)
|
60
|
+
raise AEMO::TimeError unless string.match(TIMESTAMP12_PATTERN)
|
61
|
+
|
62
|
+
::Time.find_zone(NEMTIMEZONE).strptime(string, TIMESTAMP12)
|
63
|
+
end
|
64
|
+
|
65
|
+
# Parse an 8 character date.
|
66
|
+
#
|
67
|
+
# @param [String] string
|
68
|
+
# @return [Time]
|
69
|
+
def parse_timestamp8(string)
|
70
|
+
raise AEMO::TimeError unless string.match(TIMESTAMP8_PATTERN)
|
71
|
+
|
72
|
+
::Time.find_zone(NEMTIMEZONE).strptime(string, TIMESTAMP8)
|
73
|
+
end
|
74
|
+
|
75
|
+
# Check if a string is a valid timestamp 14.
|
76
|
+
#
|
77
|
+
# @param [String] string
|
78
|
+
# @return [Boolean]
|
79
|
+
def valid_timestamp14?(string)
|
80
|
+
parse_timestamp14(string)
|
81
|
+
|
82
|
+
true
|
83
|
+
rescue AEMO::TimeError
|
84
|
+
false
|
85
|
+
end
|
86
|
+
|
87
|
+
# Check if a string is a valid timestamp 12.
|
88
|
+
#
|
89
|
+
# @param [String] string
|
90
|
+
# @return [Boolean]
|
91
|
+
def valid_timestamp12?(string)
|
92
|
+
parse_timestamp12(string)
|
93
|
+
|
94
|
+
true
|
95
|
+
rescue AEMO::TimeError
|
96
|
+
false
|
97
|
+
end
|
98
|
+
|
99
|
+
# Check if a string is a valid timestamp 8.
|
100
|
+
#
|
101
|
+
# @param [String] string
|
102
|
+
# @return [Boolean]
|
103
|
+
def valid_timestamp8?(string)
|
104
|
+
parse_timestamp8(string)
|
105
|
+
|
106
|
+
true
|
107
|
+
rescue AEMO::TimeError
|
108
|
+
false
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
data/lib/aemo/version.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# -*- coding: UTF-8 -*-
|
4
3
|
#
|
5
4
|
# Copyright 2014 Joel Courtney
|
6
5
|
#
|
@@ -24,7 +23,7 @@
|
|
24
23
|
# @author Joel Courtney <euphemize@gmail.com>
|
25
24
|
module AEMO
|
26
25
|
# aemo version
|
27
|
-
VERSION = '0.
|
26
|
+
VERSION = '0.6.0'
|
28
27
|
|
29
28
|
# aemo version split amongst different revisions
|
30
29
|
MAJOR_VERSION, MINOR_VERSION, REVISION = VERSION.split('.').map(&:to_i)
|
data/lib/aemo.rb
CHANGED
@@ -4,17 +4,19 @@ require 'active_support/all'
|
|
4
4
|
require 'httparty'
|
5
5
|
require 'csv'
|
6
6
|
|
7
|
-
require 'aemo/
|
8
|
-
require 'aemo/
|
9
|
-
require 'aemo/
|
10
|
-
require 'aemo/market
|
11
|
-
require 'aemo/
|
12
|
-
require 'aemo/
|
13
|
-
require 'aemo/
|
14
|
-
require 'aemo/
|
15
|
-
require 'aemo/
|
16
|
-
require 'aemo/
|
17
|
-
require 'aemo/
|
7
|
+
require 'aemo/struct'
|
8
|
+
require 'aemo/time'
|
9
|
+
require 'aemo/region'
|
10
|
+
require 'aemo/market'
|
11
|
+
require 'aemo/market/interval'
|
12
|
+
require 'aemo/market/node'
|
13
|
+
require 'aemo/meter'
|
14
|
+
require 'aemo/nem12'
|
15
|
+
require 'aemo/nmi'
|
16
|
+
require 'aemo/msats'
|
17
|
+
require 'aemo/register'
|
18
|
+
require 'aemo/version'
|
19
|
+
require 'aemo/exceptions/invalid_nmi_allocation_type'
|
18
20
|
|
19
21
|
# AEMO Module to encapsulate all AEMO classes
|
20
22
|
module AEMO
|
data/lib/data/xml_to_json.rb
CHANGED
@@ -21,7 +21,7 @@ CSV.parse(file_contents, headers: true, converters: :numeric).each do |row|
|
|
21
21
|
@mlf_data[row['TNI']] ||= { location: row['Location'],
|
22
22
|
voltage: row['Voltage'],
|
23
23
|
loss_factors: [] }
|
24
|
-
row.headers.
|
24
|
+
row.headers.grep(/^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
27
|
start: Time.parse("#{year - 1}-07-01T00:00:00+1000"),
|
@@ -74,7 +74,5 @@ end
|
|
74
74
|
output_data[code] << output_data_instance
|
75
75
|
end
|
76
76
|
|
77
|
-
File.
|
78
|
-
write_file.write(output_data.to_json)
|
79
|
-
end
|
77
|
+
File.write(File.join(@path, output_file), output_data.to_json)
|
80
78
|
end
|
data/spec/aemo_spec.rb
CHANGED
@@ -8,42 +8,60 @@ describe AEMO::Market::Interval do
|
|
8
8
|
expect(AEMO::Market::Interval::INTERVALS).to eq(trading: 'Trading', dispatch: 'Dispatch')
|
9
9
|
end
|
10
10
|
end
|
11
|
+
|
11
12
|
describe 'AEMO::Market::Interval instance methods' do
|
12
|
-
before
|
13
|
-
@interval =
|
13
|
+
before do
|
14
|
+
@interval = described_class.new('2016-03-01T00:30:00', 'REGION' => 'NSW', 'TOTALDEMAND' => 1000.23,
|
15
|
+
'RRP' => 76.54, 'PERIODTYPE' => 'TRADING')
|
14
16
|
end
|
17
|
+
|
15
18
|
it 'creates a valid interval' do
|
16
|
-
expect
|
19
|
+
expect do
|
20
|
+
described_class.new('2016-03-01T00:30:00', 'REGION' => 'NSW', 'TOTALDEMAND' => 1000.23, 'RRP' => 76.54,
|
21
|
+
'PERIODTYPE' => 'TRADING')
|
22
|
+
end.not_to raise_error
|
17
23
|
end
|
24
|
+
|
18
25
|
it 'has a trailing datetime' do
|
19
26
|
expect(@interval.datetime).to eq(Time.parse('2016-03-01T00:30:00+1000'))
|
20
27
|
end
|
28
|
+
|
21
29
|
it 'has a leading datetime' do
|
22
|
-
expect(@interval.datetime(false)).to eq(Time.parse('2016-03-01T00:00:00+1000'))
|
30
|
+
expect(@interval.datetime(trailing_edge: false)).to eq(Time.parse('2016-03-01T00:00:00+1000'))
|
23
31
|
end
|
32
|
+
|
24
33
|
it 'has a leading datetime for dispatch' do
|
25
|
-
@interval =
|
26
|
-
|
34
|
+
@interval = described_class.new('2016-03-01T00:30:00', 'REGION' => 'NSW', 'TOTALDEMAND' => 1000.23,
|
35
|
+
'RRP' => 76.54, 'PERIODTYPE' => '')
|
36
|
+
expect(@interval.datetime(trailing_edge: false)).to eq(Time.parse('2016-03-01T00:25:00+1000'))
|
27
37
|
end
|
38
|
+
|
28
39
|
it 'has an interval length' do
|
29
40
|
expect(@interval.interval_length).to eq(Time.at(300))
|
30
41
|
end
|
42
|
+
|
31
43
|
it 'is a trading interval' do
|
32
44
|
expect(@interval.interval_type).to eq(:trading)
|
33
45
|
end
|
46
|
+
|
34
47
|
it 'is a trading interval' do
|
35
|
-
expect(@interval.trading?).to
|
36
|
-
expect(@interval.dispatch?).to
|
48
|
+
expect(@interval.trading?).to be(true)
|
49
|
+
expect(@interval.dispatch?).to be(false)
|
37
50
|
end
|
51
|
+
|
38
52
|
it 'is a dispatch interval' do
|
39
|
-
@interval =
|
53
|
+
@interval = described_class.new('2016-03-01T00:30:00', 'REGION' => 'NSW', 'TOTALDEMAND' => 1000.23,
|
54
|
+
'RRP' => 76.54, 'PERIODTYPE' => '')
|
40
55
|
expect(@interval.interval_type).to eq(:dispatch)
|
41
56
|
end
|
57
|
+
|
42
58
|
it 'is a dispatch interval' do
|
43
|
-
@interval =
|
44
|
-
|
45
|
-
expect(@interval.
|
59
|
+
@interval = described_class.new('2016-03-01T00:30:00', 'REGION' => 'NSW', 'TOTALDEMAND' => 1000.23,
|
60
|
+
'RRP' => 76.54, 'PERIODTYPE' => '')
|
61
|
+
expect(@interval.trading?).to be(false)
|
62
|
+
expect(@interval.dispatch?).to be(true)
|
46
63
|
end
|
64
|
+
|
47
65
|
it 'has a valid value' do
|
48
66
|
expect(@interval.value).to eq((@interval.total_demand * @interval.rrp).round(2))
|
49
67
|
end
|
@@ -4,30 +4,32 @@ require 'spec_helper'
|
|
4
4
|
|
5
5
|
describe AEMO::Market::Node do
|
6
6
|
describe '.IDENTIFIERS' do
|
7
|
-
it '
|
7
|
+
it 'is an array' do
|
8
8
|
expect(AEMO::Market::Node::IDENTIFIERS).to be_instance_of(Array)
|
9
9
|
end
|
10
10
|
end
|
11
11
|
|
12
12
|
describe 'creating a node' do
|
13
|
-
it '
|
14
|
-
expect {
|
13
|
+
it 'raises an error if invalid region' do
|
14
|
+
expect { described_class.new('BOTTOMS') }.to raise_error(ArgumentError)
|
15
15
|
end
|
16
|
-
|
17
|
-
|
16
|
+
|
17
|
+
it 'creates if node valid' do
|
18
|
+
expect { described_class.new('NSW') }.not_to raise_error
|
18
19
|
end
|
19
20
|
end
|
20
21
|
|
21
22
|
describe 'AEMO::Region instance methods' do
|
22
|
-
before
|
23
|
-
@nsw =
|
23
|
+
before do
|
24
|
+
@nsw = described_class.new('NSW')
|
24
25
|
end
|
25
26
|
|
26
27
|
describe 'AEMO::Region dispatch information' do
|
27
|
-
it '
|
28
|
+
it 'returns current dispatch data' do
|
28
29
|
expect(@nsw.current_dispatch.count).to eq(AEMO::Market.current_dispatch(@nsw.identifier).count)
|
29
30
|
end
|
30
|
-
|
31
|
+
|
32
|
+
it 'returns current trading data' do
|
31
33
|
expect(@nsw.current_trading.count).to eq(AEMO::Market.current_trading(@nsw.identifier).count)
|
32
34
|
end
|
33
35
|
end
|
@@ -14,25 +14,26 @@ describe AEMO::Market do
|
|
14
14
|
|
15
15
|
describe '.current_dispatch' do
|
16
16
|
it 'has an array of data' do
|
17
|
-
expect(
|
17
|
+
expect(described_class.current_dispatch('NSW').class).to eq(Array)
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
21
21
|
describe '.current_trading' do
|
22
22
|
it 'has an array of data' do
|
23
|
-
expect(
|
23
|
+
expect(described_class.current_trading('NSW').class).to eq(Array)
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
27
27
|
describe '.historic_trading_by_range' do
|
28
28
|
it 'has an array of data' do
|
29
|
-
expect(
|
29
|
+
expect(described_class.historic_trading_by_range('NSW', Date.parse('2015-01-01'),
|
30
|
+
Date.parse('2015-02-28')).class).to eq(Array)
|
30
31
|
end
|
31
32
|
end
|
32
33
|
|
33
34
|
describe '.historic_trading' do
|
34
35
|
it 'has an array of data' do
|
35
|
-
expect(
|
36
|
+
expect(described_class.historic_trading('NSW', 2015, 1).class).to eq(Array)
|
36
37
|
end
|
37
38
|
end
|
38
39
|
end
|
data/spec/lib/aemo/meter_spec.rb
CHANGED
@@ -5,14 +5,14 @@ require 'spec_helper'
|
|
5
5
|
describe AEMO::Meter do
|
6
6
|
describe 'instance methods' do
|
7
7
|
it 'creates a new instance' do
|
8
|
-
expect(
|
8
|
+
expect(described_class.new).to be_a described_class
|
9
9
|
end
|
10
10
|
|
11
11
|
it 'can be initialized from MSATS mumbo jumbo' do
|
12
12
|
AEMO::MSATS.authorize('ER', 'ER', 'ER')
|
13
13
|
nmi_detail_query = AEMO::MSATS.nmi_detail('4001234567')
|
14
14
|
meter = nmi_detail_query['MeterRegister']['Meter'].first
|
15
|
-
expect(
|
15
|
+
expect(described_class.from_hash(meter)).to be_a described_class
|
16
16
|
end
|
17
17
|
end
|
18
18
|
end
|