tibber 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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 64eba9e3ecaabcac3c6fa77b2d93bdd0a4808b9399a2094987aebfef332586c2
4
+ data.tar.gz: eca76b85e9d6d79961c27048046ebe4c6d3d42a5d2432367188b50a9ec1bc10c
5
+ SHA512:
6
+ metadata.gz: fe85a0c01428961c7eb6f8ef27192ac4b49877b67d6031f37c9d850886fa5e6919bc9313d994dd9aa37fe733f77200a5be42070f015ec12245d2e4c9847e4839
7
+ data.tar.gz: 9a35eb84167e0f37606ccdce5f8340ed8e4332d856c190643c5a2c5018b6c0ef0a338b272efd1881e8c8923ffd9587ce13aac8990bd6c058e911e853dbed25d6
data/.env.template ADDED
@@ -0,0 +1,2 @@
1
+ # demo token used
2
+ TIBBER_ACCESS_TOKEN=5K4MVS-OjfWhK_4yrjOlFe1F6kJXPVf7eQYggo8ebAE
data/.gitignore ADDED
@@ -0,0 +1,45 @@
1
+ *.gem
2
+ *.rbc
3
+ /.config
4
+ /coverage/
5
+ /InstalledFiles
6
+ /pkg/
7
+ /spec/reports/
8
+ /spec/examples.txt
9
+ /test/tmp/
10
+ /test/version_tmp/
11
+ /tmp/
12
+ /data/
13
+ *.log
14
+ *.txt
15
+ *.json
16
+ *.yml
17
+ .DS_Store
18
+
19
+ # Used by dotenv library to load environment variables.
20
+ .env
21
+
22
+
23
+ ## Documentation cache and generated files:
24
+ /.yardoc/
25
+ /_yardoc/
26
+ /doc/
27
+ /rdoc/
28
+
29
+ ## Environment normalization:
30
+ /.bundle/
31
+ /vendor/bundle
32
+ /lib/bundler/man/
33
+
34
+ # for a library or gem, you might want to ignore these files since the code is
35
+ # intended to run in multiple environments; otherwise, check them in:
36
+ # Gemfile.lock
37
+ # .ruby-version
38
+ # .ruby-gemset
39
+
40
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
41
+ .rvmrc
42
+
43
+ # Used by RuboCop. Remote config files pulled in from inherit_from directive.
44
+ # .rubocop-https?--*
45
+ Gemfile.lock
data/CHANGELOG.md ADDED
@@ -0,0 +1,4 @@
1
+ ## [Unreleased]
2
+
3
+ ## [0.1.0] - 2024-02-25
4
+ - Initial release
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ # Specify your gem's dependencies in hudu.gemspec
6
+ gemspec
data/README.md ADDED
@@ -0,0 +1,102 @@
1
+ # Tibber API
2
+ [![Version](https://img.shields.io/gem/v/tibber.svg)](https://rubygems.org/gems/tibber)
3
+
4
+ This is a wrapper for the Tibber rest API.
5
+
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'tibber'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle install
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install tibber
22
+
23
+ ## Usage
24
+
25
+ Before you start making the requests to API provide the endpoint and api key using the configuration wrapping.
26
+
27
+ ```ruby
28
+ require 'tibber'
29
+ require 'logger'
30
+
31
+ # use do block
32
+ Tibber.configure do |config|
33
+ config.access_token = ENV['TIBBER_ACCESS_TOKEN']
34
+ config.logger = Logger.new(TEST_LOGGER)
35
+ end
36
+
37
+ # or configure with options hash
38
+ client = Tibber.client
39
+ client.login
40
+
41
+ ```
42
+
43
+ ## Resources
44
+ ### Authentication
45
+ ```ruby
46
+ # setup
47
+ #
48
+ begin
49
+ client = Tibber.client
50
+ client.login
51
+ rescue Tibber::AuthenticationError => e
52
+ puts "Error logging in tibber api"
53
+ puts e
54
+ end
55
+ ```
56
+
57
+
58
+
59
+ ### Graph QL Data resources
60
+ Endpoint for data related requests
61
+
62
+ ```ruby
63
+ # show todays prices
64
+ prices = client.price_info
65
+
66
+ prices.homes.each do |home|
67
+ puts "Today's prices:"
68
+ home.currentSubscription.priceInfo.today.each do |hour|
69
+ puts "#{hour.startsAt} #{hour.total} #{hour.currency} (#{hour.energy} + #{hour.tax})"
70
+ end
71
+ end
72
+
73
+ ```
74
+
75
+ |Resource|API endpoint|
76
+ |:--|:--|
77
+ |.information | returns `name userId login accountType websocketSubscriptionUrl homes including homes meteringPointData, subscriptions` and `features` |
78
+ |.price_info|price information for all `homes[id,currentSubscription{priceInfo{current,today[],tomorrow[]}}]` |
79
+ |.consumption(home_id, resolution, count)|Array of `home.consumption.nodes[]`: `from to cost unitPrice unitPriceVAT consumption consumptionUnit`|
80
+ |.send_push_notification(title, message, screen_to_open)| send notificartion ot devices and returns `successful` & `pushedToNumberOfDevices`|
81
+
82
+ ## Publishing
83
+
84
+ 1. Update version in [version.rb](lib/tibber/version.rb).
85
+ 2. Add release to [CHANGELOG.md](CHANGELOG.md)
86
+ 3. Commit.
87
+ 4. Test build.
88
+ ```
89
+ > rake build
90
+
91
+ ```
92
+ 5. Release
93
+ ```
94
+ > rake release
95
+
96
+ ## Contributing
97
+
98
+ Bug reports and pull requests are welcome on GitHub at https://github.com/jancotanis/tibber.
99
+
100
+ ## License
101
+
102
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'dotenv'
5
+ require 'rake/testtask'
6
+
7
+ Dotenv.load
8
+
9
+ #system './bin/cc-test-reporter before-build'
10
+ Rake::TestTask.new(:test) do |t|
11
+ t.libs << 'test'
12
+ t.libs << 'lib'
13
+ t.test_files = FileList['test/**/*_test.rb']
14
+ end
15
+
16
+ require 'rubocop/rake_task'
17
+ RuboCop::RakeTask.new
18
+ task default: %i[test rubocop]
19
+ #system './bin/cc-test-reporter after-build'
data/lib/tibber/api.rb ADDED
@@ -0,0 +1,35 @@
1
+ require "wrapi"
2
+ require File.expand_path('request', __dir__)
3
+ require File.expand_path('authorization', __dir__)
4
+
5
+ module Tibber
6
+ # @private
7
+ class API
8
+
9
+ # @private
10
+ attr_accessor *WrAPI::Configuration::VALID_OPTIONS_KEYS
11
+
12
+ # Creates a new API and copies settings from singleton
13
+ def initialize(options = {})
14
+ options = Tibber.options.merge(options)
15
+ WrAPI::Configuration::VALID_OPTIONS_KEYS.each do |key|
16
+ send("#{key}=", options[key])
17
+ end
18
+ end
19
+
20
+ def config
21
+ conf = {}
22
+ WrAPI::Configuration::VALID_OPTIONS_KEYS.each do |key|
23
+ conf[key] = send key
24
+ end
25
+ conf
26
+ end
27
+
28
+ include WrAPI::Connection
29
+ include WrAPI::Request
30
+ include Request::GraphQL
31
+ include WrAPI::Authentication
32
+ include Authentication
33
+
34
+ end
35
+ end
@@ -0,0 +1,19 @@
1
+ require File.expand_path('error', __dir__)
2
+
3
+ module Tibber
4
+ # Deals with authentication flow and stores it within global configuration
5
+ module Authentication
6
+
7
+ # Authorize to the Tibber portal using the access_token
8
+ # @see https://developer.tibber.com/docs/guides/calling-api
9
+ def login(options = {})
10
+ raise ConfigurationError, "Accesstoken/api-key not set" unless access_token
11
+ # only bearer token needed
12
+ # will do sanity check if token if valid
13
+ graphql_call('{viewer{name}}')
14
+ rescue GraphQLError => e
15
+ raise AuthenticationError.new e
16
+ end
17
+
18
+ end
19
+ end
@@ -0,0 +1,177 @@
1
+ require File.expand_path('api', __dir__)
2
+ require File.expand_path('const', __dir__)
3
+ require File.expand_path('error', __dir__)
4
+
5
+ module Tibber
6
+ # Wrapper for the Tibber REST API
7
+ #
8
+ # @see https://developer.tibber.com/docs/overview
9
+ class Client < API
10
+ attr_accessor :information
11
+
12
+ def initialize(options = {})
13
+ super(options)
14
+ login
15
+ @information = self.info
16
+ rescue GraphQLError => e
17
+ raise AuthenticationError.new e
18
+ end
19
+
20
+ private
21
+ def self.api_endpoint(method, query)
22
+
23
+ # all records
24
+ self.send(:define_method, method) do |params = {}|
25
+ r = graphql_call(query, params)
26
+ end
27
+ end
28
+
29
+ public
30
+ # return device information
31
+ # product_type
32
+ # product_name
33
+ # serial
34
+ # firmware_version
35
+ # api_version
36
+ # devices: HWE-P1, HWE-SKT, HWE-WTR, HWE-KWH1 and SDM230-wifi, HWE-KWH3 and SDM630-wifi
37
+ api_endpoint :info, '
38
+ {
39
+ viewer {
40
+ name
41
+ userId
42
+ login
43
+ accountType
44
+ websocketSubscriptionUrl
45
+ homes {
46
+ id
47
+ timeZone
48
+ appNickname
49
+ appAvatar
50
+ size
51
+ type
52
+ numberOfResidents
53
+ primaryHeatingSource
54
+ hasVentilationSystem
55
+ mainFuseSize
56
+ address {
57
+ address1
58
+ address2
59
+ address3
60
+ city
61
+ postalCode
62
+ country
63
+ latitude
64
+ longitude
65
+ }
66
+ meteringPointData {
67
+ consumptionEan
68
+ gridCompany
69
+ gridAreaCode
70
+ priceAreaCode
71
+ productionEan
72
+ energyTaxType
73
+ vatType
74
+ estimatedAnnualConsumption
75
+ }
76
+ features {
77
+ realTimeConsumptionEnabled
78
+ }
79
+ subscriptions {
80
+ id
81
+ validFrom
82
+ validTo
83
+ status
84
+ priceRating {
85
+ thresholdPercentages {
86
+ high low
87
+ }
88
+ hourly {
89
+ minEnergy maxEnergy
90
+ minTotal maxTotal
91
+ currency
92
+ }
93
+ daily {
94
+ minEnergy maxEnergy
95
+ minTotal maxTotal
96
+ currency
97
+ }
98
+ monthly {
99
+ minEnergy maxEnergy
100
+ minTotal maxTotal
101
+ currency
102
+ }
103
+ }
104
+ }
105
+ }
106
+ }
107
+ }'
108
+ api_endpoint :price_info, '
109
+ {
110
+ viewer {
111
+ homes {
112
+ id
113
+ currentSubscription{
114
+ priceInfo{
115
+ current{
116
+ startsAt
117
+ total
118
+ energy
119
+ tax
120
+ currency
121
+ }
122
+ today {
123
+ startsAt
124
+ total
125
+ energy
126
+ tax
127
+ currency
128
+ }
129
+ tomorrow {
130
+ startsAt
131
+ total
132
+ energy
133
+ tax
134
+ currency
135
+ }
136
+ }
137
+ }
138
+ }
139
+ }
140
+ }'
141
+ api_endpoint:_send_push_notification, '
142
+ mutation {
143
+ sendPushNotification(input: {
144
+ title: "%{title}",
145
+ message: "%{message}",
146
+ screenToOpen: %{screen_to_open}
147
+ }){
148
+ successful
149
+ pushedToNumberOfDevices
150
+ }
151
+ }'
152
+ def send_push_notification(title, message, screen_to_open)
153
+ _send_push_notification({ title: title, message: message, screen_to_open: screen_to_open }).sendPushNotification
154
+ end
155
+ api_endpoint :_consumption, '
156
+ {
157
+ viewer {
158
+ home(id:"%{id}") {
159
+ consumption(resolution: %{resolution}, last: %{count}) {
160
+ nodes {
161
+ from
162
+ to
163
+ cost
164
+ unitPrice
165
+ unitPriceVAT
166
+ consumption
167
+ consumptionUnit
168
+ }
169
+ }
170
+ }
171
+ }
172
+ }'
173
+ def consumption(home_id, resolution, count)
174
+ _consumption({ id: home_id, resolution: resolution, count: count })
175
+ end
176
+ end
177
+ end
@@ -0,0 +1,22 @@
1
+
2
+ module Tibber
3
+ class Enum
4
+ def self.enum(array)
5
+ array.each do |c|
6
+ const_set c,c
7
+ end
8
+ end
9
+ end
10
+ class Screens < Enum
11
+ enum %w[HOME REPORTS CONSUMPTION COMPARISON DISAGGREGATION HOME_PROFILE CUSTOMER_PROFILE METER_READING NOTIFICATIONS INVOICES]
12
+ end
13
+ class Resolution < Enum
14
+ enum %w[HOURLY DAILY WEEKLY MONTHLY ANNUAL]
15
+ end
16
+ class HomeType < Enum
17
+ enum %w[APARTMENT ROWHOUSE HOUSE COTTAGE]
18
+ end
19
+ class Avatar < Enum
20
+ enum %w[APARTMENT ROWHOUSE FLOORHOUSE1 FLOORHOUSE2 FLOORHOUSE3 COTTAGE CASTLE]
21
+ end
22
+ end
@@ -0,0 +1,15 @@
1
+ module Tibber
2
+
3
+ # Generic error to be able to rescue all Hudu errors
4
+ class TibberError < StandardError; end
5
+
6
+ # GraphQL returns error
7
+ class GraphQLError < TibberError; end
8
+
9
+ # GraphQL returns error
10
+ class ConfigurationError < TibberError; end
11
+
12
+ # Issue authenticting
13
+ class AuthenticationError < TibberError; end
14
+
15
+ end
@@ -0,0 +1,37 @@
1
+ require 'faraday'
2
+
3
+ module Tibber
4
+ # Deals with requests
5
+ module Request
6
+
7
+ # JSON-RPC is a stateless, light-weight remote procedure call (RPC) protocol. Primarily this
8
+ # specification defines several data structures and the rules around their processing. It is
9
+ # transport agnostic in that the concepts can be used within the same process, over sockets, over
10
+ # http, or in many various message passing environments. It uses JSON (RFC 4627) as data format.
11
+ #
12
+ # https://www.jsonrpc.org/specification
13
+ module GraphQL
14
+
15
+ def graphql_call(query, params = nil)
16
+ query = (query % params) if params && params.size > 0
17
+ options = {
18
+ "query": query
19
+ }
20
+ result = post( '', options )
21
+ raise GraphQLError.new(result.body['errors']) if result.body['errors']
22
+ data = result.body['data']
23
+ WrAPI::Request::Entity.create(data['viewer'] ? data['viewer'] : data)
24
+
25
+ rescue Faraday::BadRequestError => e
26
+ body = e.response[:body]
27
+ if body && body['errors']
28
+ error = body['errors']
29
+ else
30
+ error = e.to_s
31
+ end
32
+ raise GraphQLError.new(error)
33
+ end
34
+
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Tibber
4
+ VERSION = '0.1.0'
5
+ end
data/lib/tibber.rb ADDED
@@ -0,0 +1,23 @@
1
+ require "wrapi"
2
+ require File.expand_path('tibber/client', __dir__)
3
+ require File.expand_path('tibber/version', __dir__)
4
+
5
+ module Tibber
6
+ extend WrAPI::Configuration
7
+ extend WrAPI::RespondTo
8
+
9
+ DEFAULT_UA = "Ruby Tibber API client #{Tibber::VERSION}".freeze
10
+ DEFAULT_ENDPOINT = 'https://api.tibber.com/v1-beta/gql'.freeze
11
+ #
12
+ # @return [Hudu::Client]
13
+ def self.client(options = {})
14
+ Tibber::Client.new({ user_agent: DEFAULT_UA, endpoint: DEFAULT_ENDPOINT }.merge(options))
15
+ end
16
+
17
+ def self.reset
18
+ super
19
+ self.endpoint = nil
20
+ self.user_agent = DEFAULT_UA
21
+ self.endpoint = DEFAULT_ENDPOINT
22
+ end
23
+ end
data/tibber.gemspec ADDED
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'lib/tibber/version'
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = 'tibber'
7
+ s.version = Tibber::VERSION
8
+ s.authors = ['Janco Tanis']
9
+ s.email = 'gems@jancology.com'
10
+ s.license = 'MIT'
11
+
12
+ s.summary = 'A Ruby wrapper for the Tibber APIs (readonly)'
13
+ s.homepage = 'https://rubygems.org/gems/tibber'
14
+
15
+ s.required_ruby_version = Gem::Requirement.new('>= 2.4.0')
16
+
17
+ s.metadata['homepage_uri'] = s.homepage
18
+ s.metadata['source_code_uri'] = 'https://github.com/jancotanis/tibber'
19
+
20
+ # Specify which files should be added to the gem when it is released.
21
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
22
+ s.files = Dir.chdir(File.expand_path(__dir__)) do
23
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) }
24
+ end
25
+ s.bindir = 'exe'
26
+ s.executables = s.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
27
+ s.require_paths = ['lib']
28
+
29
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
30
+ s.platform = Gem::Platform::RUBY
31
+ s.add_runtime_dependency 'faraday'
32
+ s.add_runtime_dependency 'wrapi', ">= 0.3.0"
33
+ s.add_development_dependency 'dotenv'
34
+ s.add_development_dependency 'minitest'
35
+ s.add_development_dependency 'simplecov'
36
+ s.add_development_dependency 'rubocop'
37
+ end
metadata ADDED
@@ -0,0 +1,143 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: tibber
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Janco Tanis
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2024-02-26 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: faraday
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: wrapi
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 0.3.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: 0.3.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: dotenv
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: minitest
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: simplecov
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rubocop
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ description:
98
+ email: gems@jancology.com
99
+ executables: []
100
+ extensions: []
101
+ extra_rdoc_files: []
102
+ files:
103
+ - ".env.template"
104
+ - ".gitignore"
105
+ - CHANGELOG.md
106
+ - Gemfile
107
+ - README.md
108
+ - Rakefile
109
+ - lib/tibber.rb
110
+ - lib/tibber/api.rb
111
+ - lib/tibber/authorization.rb
112
+ - lib/tibber/client.rb
113
+ - lib/tibber/const.rb
114
+ - lib/tibber/error.rb
115
+ - lib/tibber/request.rb
116
+ - lib/tibber/version.rb
117
+ - tibber.gemspec
118
+ homepage: https://rubygems.org/gems/tibber
119
+ licenses:
120
+ - MIT
121
+ metadata:
122
+ homepage_uri: https://rubygems.org/gems/tibber
123
+ source_code_uri: https://github.com/jancotanis/tibber
124
+ post_install_message:
125
+ rdoc_options: []
126
+ require_paths:
127
+ - lib
128
+ required_ruby_version: !ruby/object:Gem::Requirement
129
+ requirements:
130
+ - - ">="
131
+ - !ruby/object:Gem::Version
132
+ version: 2.4.0
133
+ required_rubygems_version: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - - ">="
136
+ - !ruby/object:Gem::Version
137
+ version: '0'
138
+ requirements: []
139
+ rubygems_version: 3.2.12
140
+ signing_key:
141
+ specification_version: 4
142
+ summary: A Ruby wrapper for the Tibber APIs (readonly)
143
+ test_files: []