ce-greenbutton 0.1.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 +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
|