ce-greenbutton 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Gemfile +5 -0
- data/LICENSE.txt +21 -0
- data/README.md +162 -0
- data/Rakefile +2 -0
- data/lib/ce-greenbutton/elements/gb_application_information.rb +17 -0
- data/lib/ce-greenbutton/elements/gb_content.rb +26 -0
- data/lib/ce-greenbutton/elements/gb_data_feed.rb +34 -0
- data/lib/ce-greenbutton/elements/gb_entry.rb +68 -0
- data/lib/ce-greenbutton/elements/gb_interval.rb +21 -0
- data/lib/ce-greenbutton/elements/gb_interval_block.rb +24 -0
- data/lib/ce-greenbutton/elements/gb_interval_reading.rb +22 -0
- data/lib/ce-greenbutton/elements/gb_local_time_parameters.rb +50 -0
- data/lib/ce-greenbutton/elements/gb_reading_type.rb +23 -0
- data/lib/ce-greenbutton/elements/gb_usage_point.rb +20 -0
- data/lib/ce-greenbutton/interpreters/electricity_interpreter.rb +114 -0
- data/lib/ce-greenbutton/model/gb_data.rb +30 -0
- data/lib/ce-greenbutton/model/gb_data_description.rb +41 -0
- data/lib/ce-greenbutton/model/gb_data_reading.rb +23 -0
- data/lib/ce-greenbutton/parser.rb +54 -0
- data/lib/ce-greenbutton/ruby_extensions.rb +23 -0
- data/lib/ce-greenbutton/utils.rb +136 -0
- data/lib/ce-greenbutton/version.rb +3 -0
- data/lib/ce-greenbutton.rb +352 -0
- metadata +160 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: b411fe5d5b0acdab84cbf12802c81c41925f4003
|
4
|
+
data.tar.gz: 90fedbb838bf0ff0afad023f0b9adba288c23728
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 067ceefd90b3d862db54711d73206119a024cbdb19225bfc956a35ba1ae5aca10f8c7e068119002412d02eff8fc02121d022dc661a878db4ee92bfa3a7442790
|
7
|
+
data.tar.gz: 9a010716a45917e24cc70900bb040ff0a3b2f14b40dc26d9e57470e2c1ac2e6554935ae7e961d9dfe8e53c730e710d8b462346083b42ef0cc005b3db3b162a5b
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2015 TODO: Write your name
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,162 @@
|
|
1
|
+
# Overview
|
2
|
+
GreenButton gem is a Ruby wrapper for the [Green Button](http://www.greenbuttondata.org) Data. It allows third-party applications to retrieve the GreenButton data in the form of handy Ruby objects hiding the details of the XML representation and parsing.
|
3
|
+
|
4
|
+
## About the module
|
5
|
+
The GreenButton gem is designed for extendability and scalability. It provides a framework for processing the GreenButton data. It currently supports only the electricity consumption data, but plugins can be easily adapted to support new kinds of data.
|
6
|
+
|
7
|
+
The increased size of data by time was a significant factor in designing this module. To support this expected size of data, the [SAX parsing technique] is leveraged in this module.
|
8
|
+
|
9
|
+
### Why SAX and why sax-machine?
|
10
|
+
Unlike [DOM](http://en.wikipedia.org/wiki/Document_Object_Model), SAX need not to load the whole file into memory for parsing. It is an event driven parsing.
|
11
|
+
As we don't need power featchers of DOM like XPath for example, so SAX is ideal for data size scalability.
|
12
|
+
|
13
|
+
|
14
|
+
The [SAX Machine](https://github.com/pauldix/sax-machine) provides a simple and elegant binding interface that binds xml elements to Ruby objects and properties.
|
15
|
+
|
16
|
+
## Setup Prerequisites
|
17
|
+
1. [Latest Ruby SDK] (https://www.ruby-lang.org/en/)
|
18
|
+
[bundler](http://bundler.io/) is used to build and manage dependency.
|
19
|
+
2. [bundler](http://bundler.io/) is used to build and manage dependency.
|
20
|
+
3. [TomDoc](http://www.rubydoc.info/gems/tomdoc/0.2.5/frames#Installation) is used
|
21
|
+
|
22
|
+
|
23
|
+
|
24
|
+
|
25
|
+
## Installation
|
26
|
+
|
27
|
+
Using [bundler](http://bundler.io/), add this line to your application's Gemfile:
|
28
|
+
|
29
|
+
```ruby
|
30
|
+
gem 'greenbutton'
|
31
|
+
```
|
32
|
+
|
33
|
+
And then execute:
|
34
|
+
|
35
|
+
$ bundle
|
36
|
+
|
37
|
+
Or install it yourself as:
|
38
|
+
|
39
|
+
$ gem install greenbutton
|
40
|
+
|
41
|
+
The parser uses [SAX Machine](https://github.com/pauldix/sax-machine) and will install it as dependency.
|
42
|
+
|
43
|
+
## Usage
|
44
|
+
A typical scenario of the module usage will be like this
|
45
|
+
|
46
|
+
The following will download and parse all data for subscription
|
47
|
+
|
48
|
+
```ruby
|
49
|
+
require 'greenbutton'
|
50
|
+
GreenButton.config(reg_access_token: "your access token",
|
51
|
+
application_information_url: "http://app_info_url")
|
52
|
+
gb = GreenButton.download_data('your access token', 'http://greenbutton.data.url')
|
53
|
+
```
|
54
|
+
|
55
|
+
The following will download and parse all 2013 data for subscription
|
56
|
+
|
57
|
+
```ruby
|
58
|
+
require 'greenbutton'
|
59
|
+
GreenButton.config(reg_access_token: "your access token",
|
60
|
+
application_information_url: "http://app_info_url")
|
61
|
+
gb = GreenButton.download_data('your access token', 'http://greenbutton.data.url'
|
62
|
+
Date.new(2013,1,1), Date.new(2013,12,31))
|
63
|
+
```
|
64
|
+
### Notes on usage
|
65
|
+
1. The access token is an OAuth2 access token.
|
66
|
+
2. The GreenButton.config must be called before the first call to download_data
|
67
|
+
3. You can test real data with the following values
|
68
|
+
* registration access token: d89bb056-0f02-4d47-9fd2-ec6a19ba8d0c
|
69
|
+
* application information url: https://services.greenbuttondata.org:443/DataCustodian/espi/1_1/resource/ApplicationInformation/2
|
70
|
+
* access_token: 688b026c-665f-4994-9139-6b21b13fbeee
|
71
|
+
* data url (resource): https://services.greenbuttondata.org/DataCustodian/espi/1_1/resource/Batch/Subscription/6
|
72
|
+
|
73
|
+
|
74
|
+
**Note, the call to `config` is mandatory before the first usage of the module.**
|
75
|
+
|
76
|
+
the returning result of the download_data call is an array of GbDataDescription
|
77
|
+
and it can be accessed like that.
|
78
|
+
|
79
|
+
```ruby
|
80
|
+
gb_data_descriptions.each do |gb_data_desc|
|
81
|
+
gb_data = gb_data_desc.gb_data_array.first
|
82
|
+
gb_data_reading = gb_data.interval_readings.first
|
83
|
+
puts gb_data_reading.cost
|
84
|
+
end
|
85
|
+
```
|
86
|
+
|
87
|
+
|
88
|
+
## Limitations
|
89
|
+
1. Only the electricity consumption data is supported.
|
90
|
+
2. Only required data is extracted from the XML. For full list of required data,
|
91
|
+
check the `GbDataDescription`, `GbData` and `GbDataReading` classes in the
|
92
|
+
`model` directory.
|
93
|
+
|
94
|
+
## Extending Notes
|
95
|
+
The module is designed to ease extension in the following paths
|
96
|
+
|
97
|
+
1. Extract more information: that will be done by adding more elements to the
|
98
|
+
parser in "greenbutton/elements"
|
99
|
+
2. Support more interpreters for different GreenButton data (like 'gas' for
|
100
|
+
example). This will be done by adding the interpreter implementation in the
|
101
|
+
"greenbutton/interpreters" directory.
|
102
|
+
|
103
|
+
### Supporting new kind of GreenButton data
|
104
|
+
1. Implement the new interpreter. Name the file as <service kind name>_interpreter.rb and put it in the interpreters folder.
|
105
|
+
**NOTE that this is very important as without this naming convention, the module may not be loaded as expected.**
|
106
|
+
2. Take the provided electricity_interpreter as a guide for the expected data.
|
107
|
+
3. It is preferred to use the following names for the different data kinds.
|
108
|
+
Using those names will make the interpreter loaded automatically.
|
109
|
+
|
110
|
+
```ruby
|
111
|
+
SERVICEKIND_NAMES = {
|
112
|
+
0 => 'electricity',
|
113
|
+
1 => 'gas',
|
114
|
+
2 => 'water',
|
115
|
+
3 => 'time',
|
116
|
+
4 => 'heat',
|
117
|
+
5 => 'refuse',
|
118
|
+
6 => 'sewerage',
|
119
|
+
7 => 'rates',
|
120
|
+
8 => 'tvLicence',
|
121
|
+
9 => 'internet'
|
122
|
+
}
|
123
|
+
```
|
124
|
+
## Code Documentation
|
125
|
+
[TomDoc Notation](http://tomdoc.org/) was used to document code in this gem.
|
126
|
+
|
127
|
+
### TomDoc generation
|
128
|
+
To generate the docs:
|
129
|
+
|
130
|
+
* The latest development version of the [TomDoc tool](https://github.com/defunkt/tomdoc) should be used as the published version seems to be out-dated. Refer to [TomDoc Local Development] (https://github.com/defunkt/tomdoc#local-dev) for instructions.
|
131
|
+
* Use the console format (default), the HTML generator will not detect all docs.
|
132
|
+
* To generate the console docs, just issue the following command for each file
|
133
|
+
|
134
|
+
$ruby -rubygems /path/to/cloned/tomdoc/bin/tomdoc /path/to/tomdoced/code.rb
|
135
|
+
|
136
|
+
## Test
|
137
|
+
### Local data
|
138
|
+
Run a local web server on port 8123 and serve files under the `test_files` directory.
|
139
|
+
Using [NodeJS] (www.nodejs.org)
|
140
|
+
|
141
|
+
$ npm install http-server -g
|
142
|
+
$ cd test_files
|
143
|
+
$ http-server -p 8123
|
144
|
+
**Note** You may need admin (root) privilege to install node/http-server
|
145
|
+
|
146
|
+
From the base directory of the module (the directory containing the .gemspec file.
|
147
|
+
|
148
|
+
$ bundle install
|
149
|
+
$ bundle exec rspec
|
150
|
+
|
151
|
+
Coverage reports will be found under the `coverage` subfolder.
|
152
|
+
|
153
|
+
## GreenButton API reference
|
154
|
+
- [Green Button Home](http://www.greenbuttondata.org)
|
155
|
+
- [Green Button API sandbox](http://energyos.github.io/OpenESPI-GreenButton-API-Documentation/API/)
|
156
|
+
- [GReen Button Concept overview](http://www.greenbuttondata.org/developers/)
|
157
|
+
|
158
|
+
|
159
|
+
### Reference this Ruby Gem Documentation
|
160
|
+
`tomdoc` was used to generate documentation files for this gem. The generated files are included in `docs` directory.
|
161
|
+
|
162
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
# Copyright (C) 2015 TopCoder Inc., All Rights Reserved.
|
2
|
+
require 'sax-machine'
|
3
|
+
module GreenButton
|
4
|
+
module Parser
|
5
|
+
# a sax-machine mapping for the ApplicationInformation structure.
|
6
|
+
#
|
7
|
+
# For example
|
8
|
+
# app_info = GbApplicationInformation.parse(open(application_information.xml))
|
9
|
+
#
|
10
|
+
# Author ahmed.seddiq
|
11
|
+
# Version 1.0
|
12
|
+
class GbApplicationInformation
|
13
|
+
include SAXMachine
|
14
|
+
element :'espi:dataCustodianId', as: :data_custodian_id
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# Copyright (C) 2015 TopCoder Inc., All Rights Reserved.
|
2
|
+
require 'sax-machine'
|
3
|
+
require 'ce-greenbutton/elements/gb_interval_block'
|
4
|
+
require 'ce-greenbutton/elements/gb_usage_point'
|
5
|
+
require 'ce-greenbutton/elements/gb_local_time_parameters'
|
6
|
+
require 'ce-greenbutton/elements/gb_reading_type'
|
7
|
+
|
8
|
+
module GreenButton
|
9
|
+
module Parser
|
10
|
+
# a sax-machine mapping for the Content structure
|
11
|
+
#
|
12
|
+
# For example:
|
13
|
+
# content = GbContent.parse(open(content.xml))
|
14
|
+
#
|
15
|
+
#
|
16
|
+
# Author: ahmed.seddiq
|
17
|
+
# Version: 1.0
|
18
|
+
class GbContent
|
19
|
+
include SAXMachine
|
20
|
+
element :'espi:UsagePoint', class: GbUsagePoint, as: :usage_point
|
21
|
+
element :'espi:IntervalBlock', class: GbIntervalBlock, as: :interval_block
|
22
|
+
element :'espi:LocalTimeParameters', class: GbLocalTimeParameters, as: :local_time_parameters
|
23
|
+
element :'espi:ReadingType', class: GbReadingType, as: :reading_type
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# Copyright (C) 2015 TopCoder Inc., All Rights Reserved.
|
2
|
+
require 'sax-machine'
|
3
|
+
require 'ce-greenbutton/elements/gb_entry'
|
4
|
+
|
5
|
+
module GreenButton
|
6
|
+
module Parser
|
7
|
+
# a sax-machine mapping for the espi:DataFeed structure
|
8
|
+
#
|
9
|
+
# For example:
|
10
|
+
# data_feed = GbDataFeed.parse(open(data_feed.xml))
|
11
|
+
#
|
12
|
+
#
|
13
|
+
# Author: ahmed.seddiq
|
14
|
+
# Version: 1.0
|
15
|
+
class GbDataFeed
|
16
|
+
include SAXMachine
|
17
|
+
elements :entry, class: GbEntry, as: :entries
|
18
|
+
|
19
|
+
# Get the related entry to the given entry of the given type
|
20
|
+
#
|
21
|
+
# entry - the parent entry.
|
22
|
+
# type - the type of the required entry,e.g. 'MeterReading'
|
23
|
+
#
|
24
|
+
# Note: This method should be only called on instances returned from Parser.parse
|
25
|
+
# method.
|
26
|
+
#
|
27
|
+
# Returns the related GbEntry
|
28
|
+
def get_related (entry, type)
|
29
|
+
related_entry_key = entry.related[type] unless entry.related.nil?
|
30
|
+
self.entries[related_entry_key]
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# Copyright (C) 2015 TopCoder Inc., All Rights Reserved.
|
2
|
+
require 'sax-machine'
|
3
|
+
require 'ce-greenbutton/elements/gb_content'
|
4
|
+
module GreenButton
|
5
|
+
module Parser
|
6
|
+
# a sax-machine mapping for the Entry structure
|
7
|
+
#
|
8
|
+
# For example:
|
9
|
+
# entry = GbEntry.parse(open(entry.xml))
|
10
|
+
#
|
11
|
+
#
|
12
|
+
# Author: ahmed.seddiq
|
13
|
+
# Version: 1.0
|
14
|
+
class GbEntry
|
15
|
+
include SAXMachine
|
16
|
+
|
17
|
+
# The related entries. It is a hash {entry_type => entry_url}
|
18
|
+
# entry_urls are the href value of the link element with type "related"
|
19
|
+
attr_accessor :related
|
20
|
+
|
21
|
+
# The entry type, e.g. UsagePoint, IntervalBlock,...etc
|
22
|
+
attr_accessor :type
|
23
|
+
|
24
|
+
# Extract the href of the parent Entry
|
25
|
+
element :link, as: :up, value: :href, with: {rel: 'up'}
|
26
|
+
|
27
|
+
# Extract the href of this Entry
|
28
|
+
# The type is inferred from this href
|
29
|
+
element :link, as: :self, value: :href, with: {rel: 'self'} do |url|
|
30
|
+
self.type = entry_type url
|
31
|
+
url
|
32
|
+
end
|
33
|
+
|
34
|
+
# Extract the related Entries to the :related hash.
|
35
|
+
elements :link, value: :href, with: {rel: 'related'} do |url|
|
36
|
+
if self.related.nil?
|
37
|
+
self.related = {}
|
38
|
+
end
|
39
|
+
type = entry_type url
|
40
|
+
unless type.nil?
|
41
|
+
self.related[type] = url
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
element :content, class: GbContent
|
46
|
+
|
47
|
+
element :updated do |updated|
|
48
|
+
DateTime.parse(updated).to_time
|
49
|
+
end
|
50
|
+
|
51
|
+
# Helper method to infer the entry type from the given url.
|
52
|
+
#
|
53
|
+
# url - the url
|
54
|
+
#
|
55
|
+
# Returns the entry type, e.g. UsagePoint, IntervalBlock,...etc
|
56
|
+
private
|
57
|
+
def entry_type(url)
|
58
|
+
match = /\/(\w+)(\/(\d+))*$/.match(url)
|
59
|
+
if match.nil?
|
60
|
+
nil
|
61
|
+
else
|
62
|
+
match[1]
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# Copyright (C) 2015 TopCoder Inc., All Rights Reserved.
|
2
|
+
require 'sax-machine'
|
3
|
+
|
4
|
+
module GreenButton
|
5
|
+
module Parser
|
6
|
+
# a sax-machine mapping for the espi:Interval structure
|
7
|
+
#
|
8
|
+
# For example:
|
9
|
+
# interval = GbInterval.parse(open(interval.xml))
|
10
|
+
#
|
11
|
+
#
|
12
|
+
# Author: ahmed.seddiq
|
13
|
+
# Version: 1.0
|
14
|
+
class GbInterval
|
15
|
+
include SAXMachine
|
16
|
+
element :'espi:duration', class: Integer, as: :duration
|
17
|
+
element :'espi:start', class: Integer, as: :start
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# Copyright (C) 2015 TopCoder Inc., All Rights Reserved.
|
2
|
+
|
3
|
+
require 'sax-machine'
|
4
|
+
require 'ce-greenbutton/elements/gb_interval'
|
5
|
+
require 'ce-greenbutton/elements/gb_interval_reading'
|
6
|
+
|
7
|
+
module GreenButton
|
8
|
+
module Parser
|
9
|
+
# a sax-machine mapping for the espi:IntervalBlock structure
|
10
|
+
#
|
11
|
+
# For example:
|
12
|
+
# interval_block = GbIntervalBlock.parse(open(interval_block.xml))
|
13
|
+
#
|
14
|
+
#
|
15
|
+
# Author: ahmed.seddiq
|
16
|
+
# Version: 1.0
|
17
|
+
class GbIntervalBlock
|
18
|
+
include SAXMachine
|
19
|
+
element :'espi:interval', class: GbInterval, as: :interval
|
20
|
+
elements :'espi:IntervalReading', class: GbIntervalReading, as: :readings
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# Copyright (C) 2015 TopCoder Inc., All Rights Reserved.
|
2
|
+
|
3
|
+
require 'sax-machine'
|
4
|
+
require 'ce-greenbutton/elements/gb_interval'
|
5
|
+
|
6
|
+
module GreenButton
|
7
|
+
module Parser
|
8
|
+
# a sax-machine mapping for the espi:IntervalReading structure
|
9
|
+
#
|
10
|
+
# For example:
|
11
|
+
# interval_reading = GbIntervalReading.parse(open(interval_reading.xml))
|
12
|
+
#
|
13
|
+
#
|
14
|
+
# Author: ahmed.seddiq
|
15
|
+
# Version: 1.0
|
16
|
+
class GbIntervalReading < GbInterval
|
17
|
+
include SAXMachine
|
18
|
+
element :'espi:value', class: Integer, as: :value
|
19
|
+
element :'espi:cost', class: Integer, as: :cost
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# Copyright (C) 2015 TopCoder Inc., All Rights Reserved.
|
2
|
+
|
3
|
+
require 'sax-machine'
|
4
|
+
require 'ce-greenbutton/utils'
|
5
|
+
|
6
|
+
module GreenButton
|
7
|
+
module Parser
|
8
|
+
# a sax-machine mapping for the espi:LocalTimeParameters structure
|
9
|
+
#
|
10
|
+
# For example:
|
11
|
+
# local_time_parameters = GbLocalTimeParameters.parse(open(local_time_parameters.xml))
|
12
|
+
#
|
13
|
+
#
|
14
|
+
# Author: ahmed.seddiq
|
15
|
+
# Version: 1.0
|
16
|
+
class GbLocalTimeParameters
|
17
|
+
include SAXMachine
|
18
|
+
include Utils::DSTRule
|
19
|
+
|
20
|
+
attr_accessor :dst_start_time
|
21
|
+
attr_accessor :dst_end_time
|
22
|
+
|
23
|
+
element :'espi:dstEndRule', as: :dst_end_rule do |rule|
|
24
|
+
@dst_end_time = to_time(rule)
|
25
|
+
rule
|
26
|
+
end
|
27
|
+
element :'espi:dstStartRule', as: :dst_start_rule do |rule|
|
28
|
+
@dst_start_time = to_time(rule)
|
29
|
+
rule
|
30
|
+
end
|
31
|
+
element :'espi:dstOffset', class: Integer, as: :dst_offset
|
32
|
+
element :'espi:tzOffset', class: Integer, as: :tz_offset
|
33
|
+
|
34
|
+
# Converts time to local based on the given time configuration.
|
35
|
+
#
|
36
|
+
# The time after applying the rules in the time_config
|
37
|
+
#
|
38
|
+
def local_time(time)
|
39
|
+
# apply timezone offset
|
40
|
+
time += self.tz_offset
|
41
|
+
# apply dst offset
|
42
|
+
if Time.now.between?(@dst_start_time, @dst_end_time)
|
43
|
+
time += self.dst_offset
|
44
|
+
end
|
45
|
+
Time.at(time)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# Copyright (C) 2015 TopCoder Inc., All Rights Reserved.
|
2
|
+
|
3
|
+
require 'sax-machine'
|
4
|
+
|
5
|
+
module GreenButton
|
6
|
+
module Parser
|
7
|
+
# a sax-machine mapping for the espi:ReadingType structure
|
8
|
+
#
|
9
|
+
# For example:
|
10
|
+
# reading_type = GbReadingType.parse(open(reading_type.xml))
|
11
|
+
#
|
12
|
+
#
|
13
|
+
# Author: ahmed.seddiq
|
14
|
+
# Version: 1.0
|
15
|
+
class GbReadingType
|
16
|
+
include SAXMachine
|
17
|
+
element :'espi:commodity', class: Integer, as: :commodity
|
18
|
+
element :'espi:currency', class: Integer, as: :currency
|
19
|
+
element :'espi:uom', class: Integer, as: :uom
|
20
|
+
element :'espi:powerOfTenMultiplier', class: Integer, as: :power_of_ten_multiplier
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# Copyright (C) 2015 TopCoder Inc., All Rights Reserved.
|
2
|
+
|
3
|
+
require 'sax-machine'
|
4
|
+
|
5
|
+
module GreenButton
|
6
|
+
module Parser
|
7
|
+
# a sax-machine mapping for the espi:UsagePoint structure
|
8
|
+
#
|
9
|
+
# For example:
|
10
|
+
# usage_point = GbUsagePoint.parse(open(usage_point.xml))
|
11
|
+
#
|
12
|
+
#
|
13
|
+
# Author: ahmed.seddiq
|
14
|
+
# Version: 1.0
|
15
|
+
class GbUsagePoint
|
16
|
+
include SAXMachine
|
17
|
+
element :'espi:kind', class: Integer, as: :kind
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
# Copyright (C) 2015 TopCoder Inc., All Rights Reserved.
|
2
|
+
|
3
|
+
require 'date'
|
4
|
+
require 'ce-greenbutton'
|
5
|
+
require 'ce-greenbutton/model/gb_data_description'
|
6
|
+
require 'ce-greenbutton/model/gb_data'
|
7
|
+
require 'ce-greenbutton/model/gb_data_reading'
|
8
|
+
|
9
|
+
module GreenButton
|
10
|
+
module Interpreters
|
11
|
+
# An interpreter for the Electricity GreenButton data. It can be registered
|
12
|
+
# to the GreenButton module by calling GreenButton.register_interpreter.
|
13
|
+
#
|
14
|
+
# The interpreter will be called by the GreenButton module to interpret the
|
15
|
+
# electricity GreenButton data (kind = 0)
|
16
|
+
#
|
17
|
+
# For example:
|
18
|
+
# # This call will bind this interpreter to the GreenButton data of kind=0
|
19
|
+
# GreenButton.register_interpreter(0,:electricity)
|
20
|
+
#
|
21
|
+
# Author: ahmed.seddiq
|
22
|
+
# Version: 1.0
|
23
|
+
#
|
24
|
+
module ElectricityInterpreter
|
25
|
+
|
26
|
+
# Maps the parsed GbUsagePoint to the equivalent GbDataDescription.
|
27
|
+
#
|
28
|
+
# usage_point - The parsed GbUsagePoint.
|
29
|
+
# feed - The parsed GbDataFeed. It is used to resolve related
|
30
|
+
# entries in the usage_point hierarchy.
|
31
|
+
#
|
32
|
+
# Returns the newly created GbDataDescription instance.
|
33
|
+
#
|
34
|
+
def self.get_gb_data_description (usage_point, feed)
|
35
|
+
gb_data_description = GbDataDescription.new
|
36
|
+
gb_data_description.updated = usage_point.updated
|
37
|
+
|
38
|
+
meter_readings = feed.get_related(usage_point, 'MeterReading')
|
39
|
+
raise GreenButton::InvalidGbDataError, 'Missing MeterReading data' if meter_readings.nil?
|
40
|
+
|
41
|
+
time_config = feed.get_related(usage_point, 'LocalTimeParameters')
|
42
|
+
raise GreenButton::InvalidGbDataError, 'Missing LocalTimeParameters data' if time_config.nil?
|
43
|
+
|
44
|
+
# get the actual time parameters from the entry.content
|
45
|
+
time_config = time_config.content.local_time_parameters
|
46
|
+
|
47
|
+
# We can have multiple meter readings per usage point.
|
48
|
+
unless meter_readings.is_a? Array
|
49
|
+
meter_readings = [meter_readings]
|
50
|
+
end
|
51
|
+
meter_readings.each do |meter_reading|
|
52
|
+
interpret_meter_reading(gb_data_description, meter_reading,
|
53
|
+
time_config, feed)
|
54
|
+
end
|
55
|
+
|
56
|
+
gb_data_description
|
57
|
+
end
|
58
|
+
|
59
|
+
# Interprets a single MeterReading structure. It will append all interpreted
|
60
|
+
# GbData instances to gb_data_description.gb_data_array.
|
61
|
+
#
|
62
|
+
# gb_data_description - the GbDataDescription under construction now.
|
63
|
+
# meter_reading - the GbEntry describing the MeterReading structure.
|
64
|
+
# time_config - the GbLocalTimeParameters used to convert time
|
65
|
+
# values to local.
|
66
|
+
# feed - the parsed GbDataFeed, used to resolve any related
|
67
|
+
# GbEntries
|
68
|
+
#
|
69
|
+
# Returns Nothing.
|
70
|
+
#
|
71
|
+
private
|
72
|
+
def self.interpret_meter_reading(gb_data_description, meter_reading,
|
73
|
+
time_config, feed)
|
74
|
+
reading_type = feed.get_related(meter_reading, 'ReadingType')
|
75
|
+
raise GreenButton::InvalidGbDataError, 'Missing ReadingType data' if reading_type.nil?
|
76
|
+
|
77
|
+
reading_type = reading_type.content.reading_type
|
78
|
+
gb_data_description.commodity = reading_type.commodity
|
79
|
+
gb_data_description.currency = reading_type.currency
|
80
|
+
gb_data_description.unit_of_measure = reading_type.uom
|
81
|
+
gb_data_description.power_of_ten_multiplier =
|
82
|
+
reading_type.power_of_ten_multiplier
|
83
|
+
|
84
|
+
# interval blocks
|
85
|
+
interval_blocks = feed.get_related(meter_reading, 'IntervalBlock') || []
|
86
|
+
|
87
|
+
if gb_data_description.gb_data_array.nil?
|
88
|
+
gb_data_description.gb_data_array = []
|
89
|
+
end
|
90
|
+
updated = gb_data_description.updated
|
91
|
+
interval_blocks.each do |interval_block|
|
92
|
+
updated = interval_block.updated if interval_block.updated > updated
|
93
|
+
interval_block = interval_block.content.interval_block
|
94
|
+
gb_data = GbData.new
|
95
|
+
gb_data.gb_data_description = gb_data_description
|
96
|
+
gb_data.time_duration = interval_block.interval.duration
|
97
|
+
gb_data.time_start = time_config.local_time(interval_block.interval.start)
|
98
|
+
gb_data.interval_readings = []
|
99
|
+
interval_block.readings.each do |reading|
|
100
|
+
gb_data_reading = GbDataReading.new
|
101
|
+
gb_data_reading.time_duration = reading.duration
|
102
|
+
gb_data_reading.time_start = time_config.local_time(reading.start)
|
103
|
+
gb_data_reading.value = reading.value
|
104
|
+
gb_data_reading.cost = reading.cost
|
105
|
+
gb_data.interval_readings << gb_data_reading
|
106
|
+
end
|
107
|
+
gb_data_description.gb_data_array << gb_data
|
108
|
+
end
|
109
|
+
gb_data_description.updated = time_config.local_time(updated.to_time.to_i)
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# Copyright (C) 2015 TopCoder Inc., All Rights Reserved.
|
2
|
+
require 'ce-greenbutton/utils'
|
3
|
+
|
4
|
+
# Represents an IntervalBlock structure.
|
5
|
+
#
|
6
|
+
# Author TCSASSEMBLER
|
7
|
+
# Version 1.0
|
8
|
+
class GbData
|
9
|
+
include Utils::Hash
|
10
|
+
|
11
|
+
# A reference to the owner GbDataDescription
|
12
|
+
attr_accessor :gb_data_description
|
13
|
+
|
14
|
+
# Represents the start time (local) value from the IntervalBlock -> Interval
|
15
|
+
# structure
|
16
|
+
attr_accessor :time_start
|
17
|
+
|
18
|
+
# Represents the duration value from the IntervalBlock -> Interval structure
|
19
|
+
attr_accessor :time_duration
|
20
|
+
|
21
|
+
# An array of GbDataReading
|
22
|
+
attr_accessor :interval_readings
|
23
|
+
|
24
|
+
# Returns the parsed elements as a hash with key equals the property name and
|
25
|
+
# value equals the parsed value.
|
26
|
+
def _parse
|
27
|
+
to_hash
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|