green-button-data 0.2.1 → 0.3.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 +13 -5
- data/README.md +116 -8
- data/green-button-data.gemspec +6 -1
- data/lib/green-button-data.rb +26 -1
- data/lib/green-button-data/application_information.rb +112 -0
- data/lib/green-button-data/authorization.rb +35 -0
- data/lib/green-button-data/configuration.rb +133 -0
- data/lib/green-button-data/core_ext.rb +1 -0
- data/lib/green-button-data/core_ext/string.rb +35 -0
- data/lib/green-button-data/dst.rb +57 -0
- data/lib/green-button-data/entry.rb +87 -0
- data/lib/green-button-data/feed.rb +5 -0
- data/lib/green-button-data/fetchable.rb +242 -0
- data/lib/green-button-data/interval_block.rb +38 -0
- data/lib/green-button-data/local_time_parameters.rb +31 -0
- data/lib/green-button-data/meter_reading.rb +4 -0
- data/lib/green-button-data/model_collection.rb +33 -0
- data/lib/green-button-data/parser/application_information.rb +2 -11
- data/lib/green-button-data/parser/authorization.rb +0 -4
- data/lib/green-button-data/parser/interval.rb +8 -4
- data/lib/green-button-data/parser/interval_reading.rb +4 -1
- data/lib/green-button-data/parser/local_time_parameters.rb +0 -57
- data/lib/green-button-data/parser/summary_measurement.rb +12 -0
- data/lib/green-button-data/reading_type.rb +82 -0
- data/lib/green-button-data/relations.rb +24 -0
- data/lib/green-button-data/usage_point.rb +27 -0
- data/lib/green-button-data/usage_summary.rb +36 -0
- data/lib/green-button-data/utilities.rb +27 -0
- data/lib/green-button-data/version.rb +1 -1
- data/spec/fixtures.rb +5 -0
- data/spec/fixtures/ESPIReadingType.xml +23 -535
- data/spec/fixtures/ESPIReadingTypes.xml +535 -0
- data/spec/fixtures/ESPIUsagePoint.xml +3 -3
- data/spec/fixtures/ESPIUsagePointMeterReading.xml +13 -0
- data/spec/fixtures/ESPIUsagePointMeterReadings.xml +21 -0
- data/spec/fixtures/ESPIUsagePoints.xml +822 -0
- data/spec/lib/green-button-data/application_information_spec.rb +389 -0
- data/spec/lib/green-button-data/authorization_spec.rb +91 -0
- data/spec/{green-button-data → lib/green-button-data}/core_ext/date_spec.rb +0 -0
- data/spec/{green-button-data → lib/green-button-data}/core_ext/fixnum_spec.rb +0 -0
- data/spec/lib/green-button-data/local_time_parameters_spec.rb +106 -0
- data/spec/{green-button-data → lib/green-button-data}/parser/application_information_spec.rb +4 -4
- data/spec/{green-button-data → lib/green-button-data}/parser/authorization_spec.rb +0 -12
- data/spec/{green-button-data → lib/green-button-data}/parser/entry_spec.rb +1 -1
- data/spec/{green-button-data → lib/green-button-data}/parser/interval_block_spec.rb +4 -4
- data/spec/{green-button-data → lib/green-button-data}/parser/local_time_parameter_spec.rb +0 -0
- data/spec/{green-button-data → lib/green-button-data}/parser/reading_type_spec.rb +0 -0
- data/spec/{green-button-data → lib/green-button-data}/parser/usage_point_spec.rb +0 -0
- data/spec/{green-button-data → lib/green-button-data}/parser/usage_summary_spec.rb +0 -0
- data/spec/lib/green-button-data/reading_type_spec.rb +127 -0
- data/spec/lib/green-button-data/usage_point_spec.rb +167 -0
- data/spec/{green-button-data → lib/green-button-data}/utilities_spec.rb +1 -1
- data/spec/spec_helper.rb +5 -0
- metadata +70 -17
@@ -0,0 +1,38 @@
|
|
1
|
+
module GreenButtonData
|
2
|
+
class IntervalBlock < Entry
|
3
|
+
include Utilities
|
4
|
+
|
5
|
+
attr_accessor :length, :starts_at, :ends_at, :duration
|
6
|
+
|
7
|
+
def initialize(attributes)
|
8
|
+
super
|
9
|
+
|
10
|
+
@starts_at = @interval.starts_at local: true
|
11
|
+
@ends_at = @interval.ends_at local: true
|
12
|
+
@duration = @interval.duration
|
13
|
+
@length = @interval_readings.size
|
14
|
+
end
|
15
|
+
|
16
|
+
##
|
17
|
+
# Returns an array representation of all the interval data
|
18
|
+
def to_a
|
19
|
+
result = []
|
20
|
+
|
21
|
+
@interval_readings.each do |interval_reading|
|
22
|
+
reading = {
|
23
|
+
starts_at: interval_reading.time_period.starts_at(local: true),
|
24
|
+
ends_at: interval_reading.time_period.ends_at(local: true),
|
25
|
+
duration: interval_reading.time_period.duration,
|
26
|
+
value: interval_reading.value
|
27
|
+
}
|
28
|
+
|
29
|
+
reading[:cost] = interval_reading.cost if interval_reading.cost
|
30
|
+
reading[:quality] = interval_reading.quality if interval_reading.quality
|
31
|
+
|
32
|
+
result << reading
|
33
|
+
end
|
34
|
+
|
35
|
+
return result
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module GreenButtonData
|
2
|
+
class LocalTimeParameters < Entry
|
3
|
+
include Dst
|
4
|
+
|
5
|
+
attr_accessor :dst_offset, :tz_offset
|
6
|
+
|
7
|
+
def dst_starts_at(year = Time.now.year)
|
8
|
+
byte_to_dst_datetime(@dst_start_rule, year).to_time
|
9
|
+
end
|
10
|
+
|
11
|
+
def dst_ends_at(year = Time.now.year)
|
12
|
+
byte_to_dst_datetime(@dst_end_rule, year).to_time
|
13
|
+
end
|
14
|
+
|
15
|
+
def total_offset
|
16
|
+
@dst_offset + @tz_offset
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_h
|
20
|
+
{
|
21
|
+
dst: {
|
22
|
+
starts_at: dst_starts_at,
|
23
|
+
ends_at: dst_ends_at,
|
24
|
+
offset: dst_offset
|
25
|
+
},
|
26
|
+
tz_offset: tz_offset,
|
27
|
+
total_offset: total_offset
|
28
|
+
}
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module GreenButtonData
|
2
|
+
class ModelCollection
|
3
|
+
include Enumerable
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@models = []
|
7
|
+
end
|
8
|
+
|
9
|
+
def <<(model)
|
10
|
+
@models << model
|
11
|
+
end
|
12
|
+
|
13
|
+
def each
|
14
|
+
return enum_for(:each) unless block_given?
|
15
|
+
|
16
|
+
@models.each do |model|
|
17
|
+
yield model
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def last
|
22
|
+
@models.last
|
23
|
+
end
|
24
|
+
|
25
|
+
def size
|
26
|
+
@models.size
|
27
|
+
end
|
28
|
+
|
29
|
+
def find_by_id(id)
|
30
|
+
self.find {|model| model.id.to_s == id.to_s }
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -44,17 +44,8 @@ module GreenButtonData
|
|
44
44
|
element :client_name
|
45
45
|
element :client_id
|
46
46
|
element :client_secret
|
47
|
-
element :client_id_issued_at, class: Integer
|
48
|
-
|
49
|
-
end
|
50
|
-
element :client_secret_expires_at, class: Integer do |epoch|
|
51
|
-
if epoch == 0
|
52
|
-
# 0 means don't expire; set it to distant future
|
53
|
-
DateTime.new 9999, 12, 31, 23, 59, 59
|
54
|
-
else
|
55
|
-
Time.at(normalize_epoch(epoch)).utc.to_datetime
|
56
|
-
end
|
57
|
-
end
|
47
|
+
element :client_id_issued_at, class: Integer
|
48
|
+
element :client_secret_expires_at, class: Integer
|
58
49
|
element :redirect_uri
|
59
50
|
element :software_id
|
60
51
|
element :software_version
|
@@ -12,12 +12,16 @@ module GreenButtonData
|
|
12
12
|
normalize_epoch t
|
13
13
|
end
|
14
14
|
|
15
|
-
def starts_at
|
16
|
-
|
15
|
+
def starts_at(kwargs = {})
|
16
|
+
epoch_to_time @start, kwargs
|
17
17
|
end
|
18
18
|
|
19
|
-
def ends_at
|
20
|
-
|
19
|
+
def ends_at(kwargs = {})
|
20
|
+
epoch_to_time @start + @duration, kwargs
|
21
|
+
end
|
22
|
+
|
23
|
+
def to_s
|
24
|
+
"#{starts_at} - #{ends_at}"
|
21
25
|
end
|
22
26
|
|
23
27
|
# Standard ESPI namespacing
|
@@ -4,7 +4,10 @@ module GreenButtonData
|
|
4
4
|
include SAXMachine
|
5
5
|
include Enumerations
|
6
6
|
|
7
|
-
element :cost, class: Integer
|
7
|
+
element :cost, class: Integer do |cost|
|
8
|
+
cost / 100000.0
|
9
|
+
end
|
10
|
+
|
8
11
|
element :quality, class: Integer
|
9
12
|
element :timePeriod, class: Interval, as: :time_period
|
10
13
|
element :value, class: Integer
|
@@ -43,63 +43,6 @@ module GreenButtonData
|
|
43
43
|
element :'ns0:dstEndRule', as: :dst_end_rule
|
44
44
|
element :'ns0:dstOffset', class: Integer, as: :dst_offset
|
45
45
|
element :'ns0:tzOffset', class: Integer, as: :tz_offset
|
46
|
-
|
47
|
-
private
|
48
|
-
|
49
|
-
def byte_to_dst_datetime(byte, year = Time.now.year)
|
50
|
-
# Bits 0 - 11: seconds 0 - 3599
|
51
|
-
seconds = byte & BITMASK_SECOND
|
52
|
-
|
53
|
-
# Bits 12 - 16: hours 0 - 23
|
54
|
-
hour = (byte & BITMASK_HOUR) >> BITSHIFT_HOUR
|
55
|
-
|
56
|
-
# Bits 17 - 19: day of the week; 0 = NA, 1 - 7 (Monday = 1)
|
57
|
-
weekday = (byte & BITMASK_DAY_OF_WEEK) >> BITSHIFT_DAY_OF_WEEK
|
58
|
-
|
59
|
-
# Bits 20 - 24: day of the month; 0 = NA, 1 - 31
|
60
|
-
day = (byte & BITMASK_DAY_OF_MONTH) >> BITSHIFT_DAY_OF_MONTH
|
61
|
-
|
62
|
-
# Bits 25 - 27: DST rule 0 - 7
|
63
|
-
dst_rule = (byte & BITMASK_DST_RULE) >> BITSHIFT_DST_RULE
|
64
|
-
|
65
|
-
# Bits 28 - 31: month 1 - 12
|
66
|
-
month = (byte & BITMASK_MONTH) >> BITSHIFT_MONTH
|
67
|
-
|
68
|
-
# Raise an error unless all the values are in valid range
|
69
|
-
seconds.between?(0, 3599) and hour.between?(0, 23) and
|
70
|
-
weekday.between?(1, 7) and day.between?(0, 31) and
|
71
|
-
dst_rule.between?(0, 7) and month.between?(1, 12) or
|
72
|
-
raise RangeError, 'Invalid value range'
|
73
|
-
|
74
|
-
# In Ruby, Sunday = 0 not 7
|
75
|
-
weekday = weekday == 7 ? 0 : weekday
|
76
|
-
|
77
|
-
# Check the DST rule
|
78
|
-
dst_day = if dst_rule == 1
|
79
|
-
# Rule 1: DST starts/ends on Day of Week on or after the Day of Month
|
80
|
-
day_of_month = DateTime.new year, month, day
|
81
|
-
day_offset = if weekday >= day_of_month.wday
|
82
|
-
weekday - day_of_month.wday
|
83
|
-
else
|
84
|
-
7 + weekday - day_of_month.wday
|
85
|
-
end
|
86
|
-
|
87
|
-
day_of_month + day_offset
|
88
|
-
elsif dst_rule.between?(2, 6)
|
89
|
-
# Rule 2 - 6: DST starts/ends on Nth Day of Week in given month
|
90
|
-
# Nth Day of Week (e.g. third Friday of July)
|
91
|
-
nth_weekday_of year, month, weekday, dst_rule - 1
|
92
|
-
elsif dst_rule == 7
|
93
|
-
# Rule 7: DST starts/ends on last Day of Week in given month
|
94
|
-
last_weekday_of year, month, weekday
|
95
|
-
else
|
96
|
-
# Rule 0: DST starts/ends on the Day of Month
|
97
|
-
DateTime.new year, month, day
|
98
|
-
end
|
99
|
-
|
100
|
-
# Add the hour and seconds component to the day
|
101
|
-
dst_day + Rational(hour * 3600 + seconds, 86400)
|
102
|
-
end
|
103
46
|
end
|
104
47
|
end
|
105
48
|
end
|
@@ -19,6 +19,18 @@ module GreenButtonData
|
|
19
19
|
UNIT_SYMBOL[@uom]
|
20
20
|
end
|
21
21
|
|
22
|
+
def raw_value
|
23
|
+
@value
|
24
|
+
end
|
25
|
+
|
26
|
+
def value
|
27
|
+
@value * 10.0 ** @power_of_ten_multiplier
|
28
|
+
end
|
29
|
+
|
30
|
+
def to_s
|
31
|
+
"#{value} #{uom.to_s}"
|
32
|
+
end
|
33
|
+
|
22
34
|
# ESPI Namespacing
|
23
35
|
element :'espi:powerOfTenMultiplier', class: Integer,
|
24
36
|
as: :power_of_ten_multiplier
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module GreenButtonData
|
2
|
+
class ReadingType < Entry
|
3
|
+
include Enumerations
|
4
|
+
|
5
|
+
attr_reader :consumption_tier, :cpp, :tou
|
6
|
+
|
7
|
+
def accumulation_behaviour
|
8
|
+
get_enum_symbol ACCUMULATION, @accumulation_behaviour
|
9
|
+
end
|
10
|
+
|
11
|
+
def commodity
|
12
|
+
get_enum_symbol COMMODITY, @commodity
|
13
|
+
end
|
14
|
+
|
15
|
+
def currency
|
16
|
+
get_enum_symbol CURRENCY, @currency
|
17
|
+
end
|
18
|
+
|
19
|
+
def data_qualifier
|
20
|
+
get_enum_symbol DATA_QUALIFIER, @data_qualifier
|
21
|
+
end
|
22
|
+
|
23
|
+
def default_quality
|
24
|
+
get_enum_symbol QUALITY_OF_READING, @default_quality
|
25
|
+
end
|
26
|
+
|
27
|
+
def flow_direction
|
28
|
+
get_enum_symbol FLOW_DIRECTION, @flow_direction
|
29
|
+
end
|
30
|
+
|
31
|
+
def interval_length
|
32
|
+
@interval_length
|
33
|
+
end
|
34
|
+
|
35
|
+
def kind
|
36
|
+
get_enum_symbol MEASUREMENT, @kind
|
37
|
+
end
|
38
|
+
|
39
|
+
def measuring_period
|
40
|
+
get_enum_symbol TIME_ATTRIBUTE, @measuring_period
|
41
|
+
end
|
42
|
+
|
43
|
+
def phase
|
44
|
+
get_enum_symbol PHASE_CODE, @phase
|
45
|
+
end
|
46
|
+
|
47
|
+
def scale_factor
|
48
|
+
10.0 ** @power_of_ten_multiplier
|
49
|
+
end
|
50
|
+
|
51
|
+
def time_attribute
|
52
|
+
get_enum_symbol TIME_PERIOD_OF_INTEREST, @time_attribute
|
53
|
+
end
|
54
|
+
|
55
|
+
def unit_of_measurement
|
56
|
+
get_enum_symbol UNIT_SYMBOL, @uom
|
57
|
+
end
|
58
|
+
|
59
|
+
alias_method :unit, :unit_of_measurement
|
60
|
+
alias_method :uom, :unit_of_measurement
|
61
|
+
|
62
|
+
def to_h
|
63
|
+
{
|
64
|
+
accumulation_behaviour: accumulation_behaviour,
|
65
|
+
commodity: commodity,
|
66
|
+
consumption_tier: consumption_tier,
|
67
|
+
cpp: cpp,
|
68
|
+
currency: currency,
|
69
|
+
data_qualifier: data_qualifier,
|
70
|
+
default_quality: default_quality,
|
71
|
+
flow_direction: flow_direction,
|
72
|
+
kind: kind,
|
73
|
+
measuring_period: measuring_period,
|
74
|
+
phase: phase,
|
75
|
+
scale_factor: scale_factor,
|
76
|
+
time_attribute: time_attribute,
|
77
|
+
tou: tou,
|
78
|
+
unit_of_measurement: unit_of_measurement
|
79
|
+
}
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module GreenButtonData
|
2
|
+
module Relations
|
3
|
+
|
4
|
+
##
|
5
|
+
# Extracts related URLs from an Entry
|
6
|
+
#
|
7
|
+
# ==== Arguments
|
8
|
+
#
|
9
|
+
# * +entry+ - An instance of GreenButtonData::Parser::Entry
|
10
|
+
def construct_related_urls(entry)
|
11
|
+
related_urls = {}
|
12
|
+
|
13
|
+
entry.related.each do |related_url|
|
14
|
+
match_data = /\/(\w+)(\/(\d+))*$/.match(related_url)
|
15
|
+
|
16
|
+
unless match_data.nil?
|
17
|
+
related_urls[:"#{match_data[1].underscore}"] = related_url
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
related_urls
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module GreenButtonData
|
2
|
+
class UsagePoint < Entry
|
3
|
+
include Enumerations
|
4
|
+
|
5
|
+
attr_accessor :service_category
|
6
|
+
|
7
|
+
def initialize(attributes)
|
8
|
+
super
|
9
|
+
|
10
|
+
# If deprecated usage summary name is used, create an alias
|
11
|
+
if self.class.instance_methods.grep(/electric_power_usage/).size > 0
|
12
|
+
warn "DEPRECATED: ElectricPowerUsageSummary has been renamed to UsageSummary"
|
13
|
+
singleton_class.class_eval do
|
14
|
+
alias_method :usage_summaries, :electric_power_usage_summaries
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def service_category
|
20
|
+
SERVICE[@kind]
|
21
|
+
end
|
22
|
+
|
23
|
+
def usage_summary_url
|
24
|
+
return @usage_summary_url || @electric_power_usage_summary_url
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module GreenButtonData
|
2
|
+
class UsageSummary < Entry
|
3
|
+
include Enumerations
|
4
|
+
include Utilities
|
5
|
+
|
6
|
+
attr_reader :billing_period,
|
7
|
+
:overall_consumption_last_period
|
8
|
+
|
9
|
+
attr_writer :commodity,
|
10
|
+
:quality_of_reading
|
11
|
+
|
12
|
+
def commodity
|
13
|
+
if @commodity.is_a? Numeric
|
14
|
+
COMMODITY[@commodity]
|
15
|
+
elsif @commodity.is_a? Symbol
|
16
|
+
@commodity
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def quality_of_reading
|
21
|
+
if @quality_of_reading.is_a? Numeric
|
22
|
+
QUALITY_OF_READING[@quality_of_reading]
|
23
|
+
elsif @quality_of_reading.is_a? Symbol
|
24
|
+
@quality_of_reading
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def status_timestamp(kwargs = {})
|
29
|
+
epoch_to_time @status_time_stamp, kwargs
|
30
|
+
end
|
31
|
+
|
32
|
+
def to_s
|
33
|
+
"#{@billing_period}: #{@overall_consumption_last_period}"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -34,6 +34,16 @@ module GreenButtonData
|
|
34
34
|
end
|
35
35
|
end
|
36
36
|
|
37
|
+
def epoch_to_time(epoch, kwargs = {})
|
38
|
+
time = Time.at normalize_epoch(epoch)
|
39
|
+
|
40
|
+
if kwargs[:local] == true
|
41
|
+
return time.localtime
|
42
|
+
else
|
43
|
+
return time.utc
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
37
47
|
##
|
38
48
|
# Retrieves the first Sunday of the month
|
39
49
|
#
|
@@ -102,5 +112,22 @@ module GreenButtonData
|
|
102
112
|
|
103
113
|
last_day - day_offset
|
104
114
|
end
|
115
|
+
|
116
|
+
##
|
117
|
+
# Returns a hash representation of object instance's attributes
|
118
|
+
#
|
119
|
+
# ==== Arguments
|
120
|
+
#
|
121
|
+
# * +obj+ - an object
|
122
|
+
def attributes_to_hash(obj)
|
123
|
+
attributes_hash = {}
|
124
|
+
|
125
|
+
obj.instance_variables.each do |var|
|
126
|
+
attr_name = var.to_s.delete('@').to_sym
|
127
|
+
attributes_hash[attr_name] = obj.instance_variable_get(var)
|
128
|
+
end
|
129
|
+
|
130
|
+
return attributes_hash
|
131
|
+
end
|
105
132
|
end
|
106
133
|
end
|