Skip to content

Commit

Permalink
Merge pull request #21 from jufemaiz/feature/aemo-market-historic_tra…
Browse files Browse the repository at this point in the history
…ding_by_range

Feature/aemo market historic trading by range
  • Loading branch information
jufemaiz authored Jun 24, 2016
2 parents 33c2dc9 + 11674aa commit 3808a22
Show file tree
Hide file tree
Showing 15 changed files with 2,936 additions and 36 deletions.
2 changes: 1 addition & 1 deletion Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
PATH
remote: .
specs:
aemo (0.1.29)
aemo (0.1.31)
activesupport (~> 4.2, >= 4.2.0)
httparty (~> 0.13, >= 0.13.1)
json (~> 1.8)
Expand Down
6 changes: 3 additions & 3 deletions aemo.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ Gem::Specification.new do |s|
s.name = 'aemo'
s.version = AEMO::VERSION
s.platform = Gem::Platform::RUBY
s.date = '2016-06-14'
s.date = '2016-06-24'
s.summary = 'Gem providing functionality for the Australian Energy Market Operator data'
s.description = 'Gem providing functionality for the Australian Energy Market Operator data. Supports NMIs, NEM12, MSATS Web Services and more'
s.authors = ['Joel Courtney', 'Stuart Auld']
s.email = ['[email protected]', '[email protected]']
s.authors = ['Joel Courtney', 'Stuart Auld', 'Neil Parikh']
s.email = ['[email protected]', '[email protected]', '[email protected]']
s.homepage = 'https://github.com/jufemaiz/aemo'
s.license = 'MIT'
s.files = Dir['lib/**/*', 'spec/**/*', 'bin/*']
Expand Down
2 changes: 1 addition & 1 deletion lib/aemo.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
require 'httparty'
require 'csv'

require 'aemo/region.rb'
require 'aemo/market.rb'
require 'aemo/market/interval.rb'
require 'aemo/region.rb'
require 'aemo/nem12.rb'
require 'aemo/nmi.rb'
require 'aemo/msats.rb'
Expand Down
47 changes: 47 additions & 0 deletions lib/aemo/market.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,65 @@ module Market

# Class Methods
class << self
# Return the current dispatch dataset for a region
#
# @param [String, AEMO::Region] region AEMO::Region
# @return [Array<AEMO::Market::Interval>] an array of AEMO::Market::Intervals
def current_dispatch(region)
region = AEMO::Region.new(region) if region.is_a?(String)

response = get "/mms.GRAPHS/GRAPHS/GRAPH_5#{region}1.csv"
values = parse_response(response)
values
end

# Description of method
#
# @param [String, AEMO::Region] region AEMO::Region
# @return [Array<AEMO::Market::Interval>] an array of AEMO::Market::Intervals
def current_trading(region)
region = AEMO::Region.new(region) if region.is_a?(String)

response = get "/mms.GRAPHS/GRAPHS/GRAPH_30#{region}1.csv"
values = parse_response(response)
values
end

# Return an array of historic trading values based on a start and finish
#
# @param [String, AEMO::Region] region AEMO::Region
# @param [DateTime] start this is inclusive not exclusive
# @param [DateTime] finish this is inclusive not exclusive
# @return [Array<AEMO::Market::Interval>]
def historic_trading_by_range(region, start, finish)
region = AEMO::Region.new(region) if region.is_a?(String)

required_data = []
(start..finish).map { |d| { year: d.year, month: d.month } }.uniq.each do |period|
required_data += historic_trading(region, period[:year], period[:month])
end

required_data.select { |values| values.datetime >= start && values.datetime <= finish }
end

# Return an array of historic trading values for a Year, Month and Region
# As per the historical data at
# http://www.aemo.com.au/Electricity/Data/Price-and-Demand/Aggregated-Price-and-Demand-Data-Files/Aggregated-Price-and-Demand-2011-to-2016
#
# @param [String, AEMO::Region] region AEMO::Region
# @param [Integer] year The year for the report from AEMO
# @param [Integer] month The month for the report from AEMO
# @return [Array<AEMO::Market::Interval>]
def historic_trading(region, year, month)
region = AEMO::Region.new(region) if region.is_a?(String)

month = sprintf('%02d', month)

response = get "/mms.GRAPHS/data/DATA#{year}#{month}_#{region}1.csv"
values = parse_response(response)
values
end

protected

def parse_response(response)
Expand Down
6 changes: 3 additions & 3 deletions lib/aemo/market/interval.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ class Interval

attr_accessor :datetime, :region, :total_demand, :rrp, :period_type

# @param datetime [Time]
# @param options [Hash] Hash of optional data values
# @param [Time] datetime
# @param [Hash] options Hash of optional data values
# @return [AEMO::Market::Interval]
def initialize(datetime, options = {})
@datetime = Time.parse("#{datetime} +1000")
Expand All @@ -28,7 +28,7 @@ def initialize(datetime, options = {})

# All AEMO Data operates in Australian Eastern Standard Time
# All AEMO Data aggregates to the trailing edge of the period (this makes it difficult to do daily aggregations :( )
# @param trailing_edge [Boolean] selection of either the trailing edge of the period or the rising edge of the period for the date time
# @param [Boolean] trailing_edge selection of either the trailing edge of the period or the rising edge of the period for the date time
# @return [Time] a time object of the trailing edge of the interval
def datetime(trailing_edge = true)
t = @datetime
Expand Down
27 changes: 14 additions & 13 deletions lib/aemo/nem12.rb
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ def nmi_identifier
end

# Parses the header record
# @param line [String] A single line in string format
# @param [String] line A single line in string format
# @return [Hash] the line parsed into a hash of information
def self.parse_nem12_100(line, options = {})
csv = line.parse_csv
Expand All @@ -312,7 +312,7 @@ def self.parse_nem12_100(line, options = {})
end

# Parses the NMI Data Details
# @param line [String] A single line in string format
# @param [String] line A single line in string format
# @return [Hash] the line parsed into a hash of information
def parse_nem12_200(line, _options = {})
csv = line.parse_csv
Expand Down Expand Up @@ -352,7 +352,7 @@ def parse_nem12_200(line, _options = {})
}
end

# @param line [String] A single line in string format
# @param [String] line A single line in string format
# @return [Array of hashes] the line parsed into a hash of information
def parse_nem12_300(line, options = {})
csv = line.parse_csv
Expand Down Expand Up @@ -415,7 +415,7 @@ def parse_nem12_300(line, options = {})
intervals
end

# @param line [String] A single line in string format
# @param [String] line A single line in string format
# @return [Hash] the line parsed into a hash of information
def parse_nem12_400(line)
csv = line.parse_csv
Expand Down Expand Up @@ -458,19 +458,19 @@ def parse_nem12_400(line)
interval_events
end

# @param line [String] A single line in string format
# @param [String] line A single line in string format
# @return [Hash] the line parsed into a hash of information
def parse_nem12_500(_line, _options = {})
end

# @param line [String] A single line in string format
# @param [String] line A single line in string format
# @return [Hash] the line parsed into a hash of information
def parse_nem12_900(_line, _options = {})
end

# Turns the flag to a string
#
# @param [Hash] the object of a flag
# @param [Hash] flag the object of a flag
# @return [nil, String] a hyphenated string for the flag or nil
def flag_to_s(flag)
flag_to_s = []
Expand Down Expand Up @@ -507,20 +507,21 @@ def to_csv
end.join('\n')
end

# @param path_to_file [String] the path to a file
# @return [] NEM12 object
# @param [String] path_to_file the path to a file
# @return [Array<AEMO::NEM12>] NEM12 object
def self.parse_nem12_file(path_to_file, strict = false)
parse_nem12(File.read(path_to_file), strict)
end

# @param contents [String] the path to a file
# @return [Array[AEMO::NEM12]] An array of NEM12 objects
def self.parse_nem12(contents, _strict = false)
# @param [String] contents the path to a file
# @param [Boolean] strict
# @return [Array<AEMO::NEM12>] An array of NEM12 objects
def self.parse_nem12(contents, strict = false)
file_contents = contents.tr('\r', '\n').tr('\n\n', '\n').split('\n').delete_if(&:empty?)
raise ArgumentError, 'First row should be have a RecordIndicator of 100 and be of type Header Record' unless file_contents.first.parse_csv[0] == '100'

nem12s = []
AEMO::NEM12.parse_nem12_100(file_contents.first, strict: _strict)
AEMO::NEM12.parse_nem12_100(file_contents.first, strict: strict)
file_contents.each do |line|
case line[0..2].to_i
when 200
Expand Down
18 changes: 9 additions & 9 deletions lib/aemo/nmi.rb
Original file line number Diff line number Diff line change
Expand Up @@ -427,8 +427,8 @@ class NMI

# Initialize a NMI file
#
# @param nmi [String] the National Meter Identifier (NMI)
# @param options [Hash] a hash of options
# @param [String] nmi the National Meter Identifier (NMI)
# @param [Hash] options a hash of options
# @option options [Hash] :msats_detail MSATS details as per #parse_msats_detail requirements
# @return [AEMO::NMI] an instance of AEMO::NMI is returned
def initialize(nmi, options = {})
Expand Down Expand Up @@ -461,7 +461,7 @@ def network

# A function to calculate the checksum value for a given National Meter Identifier
#
# @param checksum_value [Integer] the checksum value to check against the current National Meter Identifier's checksum value
# @param [Integer] checksum_value the checksum value to check against the current National Meter Identifier's checksum value
# @return [Boolean] whether or not the checksum is valid
def valid_checksum?(checksum_value)
checksum_value == checksum
Expand Down Expand Up @@ -590,15 +590,15 @@ def friendly_address

# Returns the meter OpenStructs for the requested status (C/R)
#
# @param status [String] the stateus [C|R]
# @param [String] status the stateus [C|R]
# @return [Array<OpenStruct>] Returns an array of OpenStructs for Meters with the status provided
def meters_by_status(status = 'C')
@meters.select { |x| x.status == status.to_s }
end

# Returns the data_stream OpenStructs for the requested status (A/I)
#
# @param status [String] the stateus [A|I]
# @param [String] status the stateus [A|I]
# @return [Array<OpenStruct>] Returns an array of OpenStructs for the current Meters
def data_streams_by_status(status = 'A')
@data_streams.select { |x| x.status == status.to_s }
Expand All @@ -620,16 +620,16 @@ def current_annual_load

# A function to validate the NMI provided
#
# @param nmi [String] the nmi to be checked
# @param [String] nmi the nmi to be checked
# @return [Boolean] whether or not the nmi is valid
def self.valid_nmi?(nmi)
((nmi.length == 10) && !nmi.match(/^([A-HJ-NP-Z\d]{10})/).nil?)
end

# A function to calculate the checksum value for a given National Meter Identifier
#
# @param nmi [String] the NMI to check the checksum against
# @param checksum_value [Integer] the checksum value to check against the current National Meter Identifier's checksum value
# @param [String] nmi the NMI to check the checksum against
# @param [Integer] checksum_value the checksum value to check against the current National Meter Identifier's checksum value
# @return [Boolean] whether or not the checksum is valid
def self.valid_checksum?(nmi, checksum_value)
nmi = AEMO::NMI.new(nmi)
Expand All @@ -638,7 +638,7 @@ def self.valid_checksum?(nmi, checksum_value)

# Find the Network for a given NMI
#
# @param nmi [String] NMI
# @param [String] nmi NMI
# @returns [Hash] The Network information
def self.network(nmi)
network = nil
Expand Down
2 changes: 1 addition & 1 deletion lib/aemo/version.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
# @author Joel Courtney <[email protected]>
module AEMO
# aemo version
VERSION = '0.1.30'.freeze
VERSION = '0.1.31'.freeze

# aemo version split amongst different revisions
MAJOR_VERSION, MINOR_VERSION, REVISION = VERSION.split('.').map(&:to_i)
Expand Down
Loading

0 comments on commit 3808a22

Please sign in to comment.