senec 0.18.0 → 0.19.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.
Files changed (82) hide show
  1. checksums.yaml +4 -4
  2. data/.DS_Store +0 -0
  3. data/.env +6 -0
  4. data/.env.test +1 -1
  5. data/.gitignore +13 -0
  6. data/.rspec_status +69 -0
  7. data/.rubocop.yml +1 -1
  8. data/.ruby-lsp/.gitignore +1 -0
  9. data/.ruby-lsp/Gemfile +6 -0
  10. data/.ruby-lsp/Gemfile.lock +170 -0
  11. data/.ruby-lsp/main_lockfile_hash +1 -0
  12. data/.ruby-lsp/needs_update +0 -0
  13. data/README.md +50 -79
  14. data/coverage/.last_run.json +5 -0
  15. data/coverage/.resultset.json +1367 -0
  16. data/coverage/.resultset.json.lock +0 -0
  17. data/coverage/assets/0.13.2/DataTables-1.10.20/images/sort_asc.png +0 -0
  18. data/coverage/assets/0.13.2/DataTables-1.10.20/images/sort_asc_disabled.png +0 -0
  19. data/coverage/assets/0.13.2/DataTables-1.10.20/images/sort_both.png +0 -0
  20. data/coverage/assets/0.13.2/DataTables-1.10.20/images/sort_desc.png +0 -0
  21. data/coverage/assets/0.13.2/DataTables-1.10.20/images/sort_desc_disabled.png +0 -0
  22. data/coverage/assets/0.13.2/application.css +1 -0
  23. data/coverage/assets/0.13.2/application.js +7 -0
  24. data/coverage/assets/0.13.2/colorbox/border.png +0 -0
  25. data/coverage/assets/0.13.2/colorbox/controls.png +0 -0
  26. data/coverage/assets/0.13.2/colorbox/loading.gif +0 -0
  27. data/coverage/assets/0.13.2/colorbox/loading_background.png +0 -0
  28. data/coverage/assets/0.13.2/favicon_green.png +0 -0
  29. data/coverage/assets/0.13.2/favicon_red.png +0 -0
  30. data/coverage/assets/0.13.2/favicon_yellow.png +0 -0
  31. data/coverage/assets/0.13.2/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
  32. data/coverage/assets/0.13.2/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
  33. data/coverage/assets/0.13.2/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
  34. data/coverage/assets/0.13.2/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  35. data/coverage/assets/0.13.2/images/ui-bg_glass_75_dadada_1x400.png +0 -0
  36. data/coverage/assets/0.13.2/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
  37. data/coverage/assets/0.13.2/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
  38. data/coverage/assets/0.13.2/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
  39. data/coverage/assets/0.13.2/images/ui-icons_222222_256x240.png +0 -0
  40. data/coverage/assets/0.13.2/images/ui-icons_2e83ff_256x240.png +0 -0
  41. data/coverage/assets/0.13.2/images/ui-icons_454545_256x240.png +0 -0
  42. data/coverage/assets/0.13.2/images/ui-icons_888888_256x240.png +0 -0
  43. data/coverage/assets/0.13.2/images/ui-icons_cd0a0a_256x240.png +0 -0
  44. data/coverage/assets/0.13.2/loading.gif +0 -0
  45. data/coverage/assets/0.13.2/magnify.png +0 -0
  46. data/coverage/coverage.json +1368 -0
  47. data/coverage/index.html +15044 -0
  48. data/lib/.DS_Store +0 -0
  49. data/lib/senec/cloud/connection.rb +96 -39
  50. data/lib/senec/cloud/error.rb +0 -6
  51. data/lib/senec/cloud/stats_overview.rb +52 -0
  52. data/lib/senec/cloud/wallboxes.rb +52 -0
  53. data/lib/senec/local/request.rb +1 -1
  54. data/lib/senec/local/state.rb +1 -0
  55. data/lib/senec/version.rb +1 -1
  56. data/lib/senec.rb +2 -2
  57. data/pkg/senec-0.1.0.gem +0 -0
  58. data/pkg/senec-0.10.0.gem +0 -0
  59. data/pkg/senec-0.11.0.gem +0 -0
  60. data/pkg/senec-0.12.0.gem +0 -0
  61. data/pkg/senec-0.13.0.gem +0 -0
  62. data/pkg/senec-0.14.0.gem +0 -0
  63. data/pkg/senec-0.15.0.gem +0 -0
  64. data/pkg/senec-0.17.0.gem +0 -0
  65. data/pkg/senec-0.17.1.gem +0 -0
  66. data/pkg/senec-0.17.2.gem +0 -0
  67. data/pkg/senec-0.18.0.gem +0 -0
  68. data/pkg/senec-0.2.0.gem +0 -0
  69. data/pkg/senec-0.3.0.gem +0 -0
  70. data/pkg/senec-0.4.0.gem +0 -0
  71. data/pkg/senec-0.5.0.gem +0 -0
  72. data/pkg/senec-0.6.0.gem +0 -0
  73. data/pkg/senec-0.6.1.gem +0 -0
  74. data/pkg/senec-0.6.2.gem +0 -0
  75. data/pkg/senec-0.7.0.gem +0 -0
  76. data/pkg/senec-0.7.1.gem +0 -0
  77. data/pkg/senec-0.7.2.gem +0 -0
  78. data/pkg/senec-0.8.0.gem +0 -0
  79. data/pkg/senec-0.9.0.gem +0 -0
  80. metadata +72 -5
  81. data/lib/senec/cloud/dashboard.rb +0 -80
  82. data/lib/senec/cloud/technical_data.rb +0 -69
data/lib/.DS_Store ADDED
Binary file
@@ -1,72 +1,129 @@
1
+ require 'faraday'
2
+ require 'json'
3
+
1
4
  module Senec
2
5
  module Cloud
6
+ BASE_URL = 'https://mein-senec.de'.freeze
7
+
3
8
  class Connection
4
- def initialize(username:, password:, token: nil)
9
+ DEFAULT_USER_AGENT = "ruby-senec/#{Senec::VERSION} (+https://github.com/solectrus/senec)".freeze
10
+ MAX_REDIRECTS = 10
11
+
12
+ def initialize(username:, password:, user_agent: DEFAULT_USER_AGENT)
5
13
  @username = username
6
14
  @password = password
7
- @token = token
15
+ @user_agent = user_agent
16
+ @cookies = {}
8
17
  end
9
18
 
10
- attr_reader :username, :password
19
+ attr_reader :username, :password, :user_agent, :cookies
11
20
 
12
21
  def authenticated?
13
- !token.nil?
14
- end
22
+ authenticate if cookies.empty?
15
23
 
16
- def systems
17
- get('/v1/senec/systems')
24
+ cookies.key?('sso.senec.com_KEYCLOAK_IDENTITY')
18
25
  end
19
26
 
20
- def default_system_id
21
- raise Error.new('No systems found!', :not_found) if systems.nil?
27
+ def authenticate
28
+ response = request_with_redirects(Cloud::BASE_URL)
29
+
30
+ # Find form with username and password inputs
31
+ form_match = find_login_form(response.body)
32
+ raise Error, 'Login form not found!' unless form_match
22
33
 
23
- systems[0]['id']
34
+ # Perform the login request with the extracted form action URL
35
+ form_action = form_match.gsub('&', '&')
36
+ request_with_redirects(
37
+ form_action, {
38
+ 'username' => username,
39
+ 'password' => password
40
+ },
41
+ )
24
42
  end
25
43
 
26
- def get(path, params: nil)
27
- return_body do
28
- connection.get(path, params, { authorization: token })
29
- end
44
+ def simple_request(url)
45
+ perform_request(url)
30
46
  end
31
47
 
32
- def post(path, data)
33
- return_body do
34
- connection.post(path, data)
48
+ def request_with_redirects(url, data = nil)
49
+ uri = URI(url)
50
+ redirect_count = 0
51
+ response = nil
52
+
53
+ loop do
54
+ response = perform_request(uri.to_s, data)
55
+ store_cookies(response)
56
+
57
+ break unless (300..399).cover?(response.status)
58
+
59
+ location = response.headers['location']
60
+ break unless location
61
+
62
+ redirect_count += 1
63
+ raise 'Too many redirects!' if redirect_count > MAX_REDIRECTS
64
+
65
+ uri = location.start_with?('http') ? URI(location) : URI.join(uri, location)
66
+ data = nil # Clear data after first request (no POST redirects)
35
67
  end
36
- end
37
68
 
38
- def token
39
- @token ||= login['token']
69
+ response
40
70
  end
41
71
 
42
72
  private
43
73
 
44
- def login
45
- post('/v1/senec/login', { username:, password: })
74
+ def find_login_form(html_body)
75
+ # Find all forms and check if they contain both username and password inputs
76
+ html_body.scan(%r{<form[^>]*action="([^"]+)"[^>]*>(.*?)</form>}m).each do |action, form_content|
77
+ has_username = form_content.match(/input[^>]*name=["']username["'][^>]*/)
78
+ has_password = form_content.match(/input[^>]*name=["']password["'][^>]*/)
79
+
80
+ return action if has_username && has_password
81
+ end
82
+
83
+ # :nocov:
84
+ nil
85
+ # :nocov:
46
86
  end
47
87
 
48
- def connection
49
- @connection ||=
50
- Faraday.new(url: 'https://app-gateway.prod.senec.dev') do |f|
51
- f.request :json
52
- f.response :json
53
-
54
- f.adapter :net_http_persistent, pool_size: 5 do |http|
55
- # :nocov:
56
- http.idle_timeout = 120
57
- # :nocov:
58
- end
88
+ def faraday
89
+ @faraday ||= Faraday.new do |f|
90
+ f.adapter :net_http_persistent, pool_size: 1 do |http|
91
+ # :nocov:
92
+ http.idle_timeout = 400
93
+ # :nocov:
59
94
  end
95
+ end
60
96
  end
61
97
 
62
- def return_body(&)
63
- response = yield
64
-
65
- unless response.success?
66
- raise Error.new("Error #{response.status}", response.status)
98
+ def perform_request(url, data = nil)
99
+ method = data ? :post : :get
100
+ faraday.public_send(method, url) do |req|
101
+ configure_request_headers(req)
102
+ if method == :post
103
+ req.body = URI.encode_www_form(data)
104
+ req.headers['content-type'] = 'application/x-www-form-urlencoded'
105
+ end
67
106
  end
107
+ end
108
+
109
+ def configure_request_headers(request)
110
+ request.headers['user-agent'] = user_agent
111
+ request.headers['connection'] = 'keep-alive'
112
+ request.headers['cookie'] = cookies.values.join('; ') unless cookies.empty?
113
+ end
68
114
 
69
- response.body
115
+ def store_cookies(response)
116
+ host = URI(response.env.url).host
117
+ cookie_header = response.headers['set-cookie']
118
+ return unless cookie_header
119
+
120
+ Array(cookie_header).each do |cookie_string|
121
+ cookie_string.split(', ').each do |cookie|
122
+ cookie_name = cookie.split('=').first
123
+ cookie_value = cookie.split(';').first
124
+ @cookies["#{host}_#{cookie_name}"] = cookie_value
125
+ end
126
+ end
70
127
  end
71
128
  end
72
129
  end
@@ -1,12 +1,6 @@
1
1
  module Senec
2
2
  module Cloud
3
3
  class Error < StandardError
4
- attr_reader :status
5
-
6
- def initialize(message, status)
7
- super(message)
8
- @status = status
9
- end
10
4
  end
11
5
  end
12
6
  end
@@ -0,0 +1,52 @@
1
+ require_relative 'connection'
2
+ require 'net/http'
3
+ require 'json'
4
+
5
+ # Model for the Senec statistics overview data.
6
+ #
7
+ # Example use:
8
+ #
9
+ # connection = Senec::Cloud::Connection.new(username: '...', password: '...')
10
+ #
11
+ # # Get the data of a specific system:
12
+ # Senec::Cloud::StatsOverview.new(connection:, system_id: 1).data
13
+ #
14
+ # # Get the data of the default system (system_id 0):
15
+ # Senec::Cloud::StatsOverview.new(connection:).data
16
+ #
17
+ module Senec
18
+ module Cloud
19
+ class StatsOverview
20
+ PATH = '/endkunde/api/status/getstatusoverview.php'.freeze
21
+
22
+ def initialize(connection: nil, system_id: 0)
23
+ raise ArgumentError unless connection
24
+
25
+ @connection = connection
26
+ @system_id = system_id
27
+ end
28
+
29
+ attr_reader :connection, :system_id
30
+
31
+ def data
32
+ @data ||= fetch_data
33
+ end
34
+
35
+ private
36
+
37
+ def fetch_data
38
+ connection.authenticate unless connection.authenticated?
39
+
40
+ uri = URI("#{Cloud::BASE_URL}#{PATH}")
41
+ uri.query = URI.encode_www_form(anlageNummer: system_id)
42
+
43
+ response = connection.simple_request(uri.to_s)
44
+ JSON.parse(response.body)
45
+ rescue JSON::ParserError
46
+ # :nocov:
47
+ raise Error, "Failed to parse response from #{PATH}"
48
+ # :nocov:
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,52 @@
1
+ require_relative 'connection'
2
+ require 'net/http'
3
+ require 'json'
4
+
5
+ # Model for the Senec wallboxes data.
6
+ #
7
+ # Example use:
8
+ #
9
+ # connection = Senec::Cloud::Connection.new(username: '...', password: '...')
10
+ #
11
+ # # Get the data of a specific system:
12
+ # Senec::Cloud::Wallboxes.new(connection:, system_id: 1).data
13
+ #
14
+ # # Get the data of the default system (system_id 0):
15
+ # Senec::Cloud::Wallboxes.new(connection:).data
16
+ #
17
+ module Senec
18
+ module Cloud
19
+ class Wallboxes
20
+ PATH = '/endkunde/api/wallboxes'.freeze
21
+
22
+ def initialize(connection: nil, system_id: 0)
23
+ raise ArgumentError unless connection
24
+
25
+ @connection = connection
26
+ @system_id = system_id
27
+ end
28
+
29
+ attr_reader :connection, :system_id
30
+
31
+ def data
32
+ @data ||= fetch_data
33
+ end
34
+
35
+ private
36
+
37
+ def fetch_data
38
+ connection.authenticate unless connection.authenticated?
39
+
40
+ uri = URI("#{Cloud::BASE_URL}#{PATH}")
41
+ uri.query = URI.encode_www_form(anlageNummer: system_id)
42
+
43
+ response = connection.simple_request(uri.to_s)
44
+ JSON.parse(response.body)
45
+ rescue JSON::ParserError
46
+ # :nocov:
47
+ raise Error, "Failed to parse response from #{PATH}"
48
+ # :nocov:
49
+ end
50
+ end
51
+ end
52
+ end
@@ -12,7 +12,7 @@ module Senec
12
12
 
13
13
  attr_reader :connection, :body, :state_names
14
14
 
15
- def perform!
15
+ def perform! # rubocop:disable Naming/PredicateMethod
16
16
  parsed_response
17
17
  true
18
18
  end
@@ -39,6 +39,7 @@ module Senec
39
39
  # Regex pattern to match the system_state_name definition in the JavaScript file
40
40
  # The file may be minimized, so we need to be flexible with whitespace and line breaks
41
41
  FILE_REGEX = /system_state_name\s*=\s*{\s*([^}]*)\s*}/m
42
+ private_constant :FILE_REGEX
42
43
 
43
44
  def response(language:)
44
45
  res = connection.get url(language:)
data/lib/senec/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Senec
2
- VERSION = '0.18.0'.freeze
2
+ VERSION = '0.19.0'.freeze
3
3
  end
data/lib/senec.rb CHANGED
@@ -4,6 +4,6 @@ require 'senec/local/state'
4
4
  require 'senec/local/request'
5
5
  require 'senec/local/error'
6
6
 
7
- require 'senec/cloud/dashboard'
8
- require 'senec/cloud/technical_data'
7
+ require 'senec/cloud/stats_overview'
8
+ require 'senec/cloud/wallboxes'
9
9
  require 'senec/cloud/error'
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: senec
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.18.0
4
+ version: 0.19.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Georg Ledermann
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 2025-01-11 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: faraday
@@ -58,19 +58,63 @@ executables: []
58
58
  extensions: []
59
59
  extra_rdoc_files: []
60
60
  files:
61
+ - ".DS_Store"
62
+ - ".env"
61
63
  - ".env.test"
64
+ - ".gitignore"
62
65
  - ".rspec"
66
+ - ".rspec_status"
63
67
  - ".rubocop.yml"
68
+ - ".ruby-lsp/.gitignore"
69
+ - ".ruby-lsp/Gemfile"
70
+ - ".ruby-lsp/Gemfile.lock"
71
+ - ".ruby-lsp/main_lockfile_hash"
72
+ - ".ruby-lsp/needs_update"
64
73
  - ".vscode/settings.json"
65
74
  - CODE_OF_CONDUCT.md
66
75
  - LICENSE
67
76
  - README.md
68
77
  - Rakefile
78
+ - coverage/.last_run.json
79
+ - coverage/.resultset.json
80
+ - coverage/.resultset.json.lock
81
+ - coverage/assets/0.13.2/DataTables-1.10.20/images/sort_asc.png
82
+ - coverage/assets/0.13.2/DataTables-1.10.20/images/sort_asc_disabled.png
83
+ - coverage/assets/0.13.2/DataTables-1.10.20/images/sort_both.png
84
+ - coverage/assets/0.13.2/DataTables-1.10.20/images/sort_desc.png
85
+ - coverage/assets/0.13.2/DataTables-1.10.20/images/sort_desc_disabled.png
86
+ - coverage/assets/0.13.2/application.css
87
+ - coverage/assets/0.13.2/application.js
88
+ - coverage/assets/0.13.2/colorbox/border.png
89
+ - coverage/assets/0.13.2/colorbox/controls.png
90
+ - coverage/assets/0.13.2/colorbox/loading.gif
91
+ - coverage/assets/0.13.2/colorbox/loading_background.png
92
+ - coverage/assets/0.13.2/favicon_green.png
93
+ - coverage/assets/0.13.2/favicon_red.png
94
+ - coverage/assets/0.13.2/favicon_yellow.png
95
+ - coverage/assets/0.13.2/images/ui-bg_flat_0_aaaaaa_40x100.png
96
+ - coverage/assets/0.13.2/images/ui-bg_flat_75_ffffff_40x100.png
97
+ - coverage/assets/0.13.2/images/ui-bg_glass_55_fbf9ee_1x400.png
98
+ - coverage/assets/0.13.2/images/ui-bg_glass_65_ffffff_1x400.png
99
+ - coverage/assets/0.13.2/images/ui-bg_glass_75_dadada_1x400.png
100
+ - coverage/assets/0.13.2/images/ui-bg_glass_75_e6e6e6_1x400.png
101
+ - coverage/assets/0.13.2/images/ui-bg_glass_95_fef1ec_1x400.png
102
+ - coverage/assets/0.13.2/images/ui-bg_highlight-soft_75_cccccc_1x100.png
103
+ - coverage/assets/0.13.2/images/ui-icons_222222_256x240.png
104
+ - coverage/assets/0.13.2/images/ui-icons_2e83ff_256x240.png
105
+ - coverage/assets/0.13.2/images/ui-icons_454545_256x240.png
106
+ - coverage/assets/0.13.2/images/ui-icons_888888_256x240.png
107
+ - coverage/assets/0.13.2/images/ui-icons_cd0a0a_256x240.png
108
+ - coverage/assets/0.13.2/loading.gif
109
+ - coverage/assets/0.13.2/magnify.png
110
+ - coverage/coverage.json
111
+ - coverage/index.html
112
+ - lib/.DS_Store
69
113
  - lib/senec.rb
70
114
  - lib/senec/cloud/connection.rb
71
- - lib/senec/cloud/dashboard.rb
72
115
  - lib/senec/cloud/error.rb
73
- - lib/senec/cloud/technical_data.rb
116
+ - lib/senec/cloud/stats_overview.rb
117
+ - lib/senec/cloud/wallboxes.rb
74
118
  - lib/senec/local/connection.rb
75
119
  - lib/senec/local/constants.rb
76
120
  - lib/senec/local/error.rb
@@ -78,6 +122,29 @@ files:
78
122
  - lib/senec/local/state.rb
79
123
  - lib/senec/local/value.rb
80
124
  - lib/senec/version.rb
125
+ - pkg/senec-0.1.0.gem
126
+ - pkg/senec-0.10.0.gem
127
+ - pkg/senec-0.11.0.gem
128
+ - pkg/senec-0.12.0.gem
129
+ - pkg/senec-0.13.0.gem
130
+ - pkg/senec-0.14.0.gem
131
+ - pkg/senec-0.15.0.gem
132
+ - pkg/senec-0.17.0.gem
133
+ - pkg/senec-0.17.1.gem
134
+ - pkg/senec-0.17.2.gem
135
+ - pkg/senec-0.18.0.gem
136
+ - pkg/senec-0.2.0.gem
137
+ - pkg/senec-0.3.0.gem
138
+ - pkg/senec-0.4.0.gem
139
+ - pkg/senec-0.5.0.gem
140
+ - pkg/senec-0.6.0.gem
141
+ - pkg/senec-0.6.1.gem
142
+ - pkg/senec-0.6.2.gem
143
+ - pkg/senec-0.7.0.gem
144
+ - pkg/senec-0.7.1.gem
145
+ - pkg/senec-0.7.2.gem
146
+ - pkg/senec-0.8.0.gem
147
+ - pkg/senec-0.9.0.gem
81
148
  homepage: https://github.com/solectrus/senec
82
149
  licenses:
83
150
  - MIT
@@ -100,7 +167,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
100
167
  - !ruby/object:Gem::Version
101
168
  version: '0'
102
169
  requirements: []
103
- rubygems_version: 3.6.2
170
+ rubygems_version: 3.7.1
104
171
  specification_version: 4
105
172
  summary: Unofficial Ruby Client for SENEC Home
106
173
  test_files: []
@@ -1,80 +0,0 @@
1
- require_relative 'connection'
2
-
3
- # Model for the Senec dashboard data.
4
- #
5
- # Example use:
6
- #
7
- # connection = Senec::Cloud::Connection.new(username: '...', password: '...')
8
- #
9
- # # Get the data of a specific system:
10
- # Dashboard[connection].find('123456').data
11
- #
12
- # # Get the data of the default system:
13
- # Dashboard[connection].first.data
14
- #
15
- # By default, it returns v1 data. To get v2 data, use:
16
- #
17
- # Dashboard[connection].find('123456').data(version: 'v2')
18
- # or
19
- # Dashboard[connection].first.data(version: 'v2')
20
- #
21
- module Senec
22
- module Cloud
23
- class Dashboard
24
- AVAILABLE_VERSIONS = %w[v1 v2].freeze
25
- DEFAULT_VERSION = 'v1'.freeze
26
-
27
- class Finder
28
- def initialize(connection)
29
- @connection = connection
30
- end
31
- attr_reader :connection
32
-
33
- def find(system_id)
34
- Dashboard.new(connection:, system_id:)
35
- end
36
-
37
- def first
38
- find(connection.default_system_id)
39
- end
40
- end
41
-
42
- def self.[](connection)
43
- Finder.new(connection)
44
- end
45
-
46
- def initialize(connection: nil, system_id: nil, data: nil)
47
- raise ArgumentError unless connection.nil? ^ data.nil?
48
-
49
- @connection = connection
50
- @system_id = system_id
51
-
52
- # Useful for testing only
53
- @data = {
54
- 'v1' => data,
55
- 'v2' => data
56
- }
57
- end
58
-
59
- def data(version: DEFAULT_VERSION)
60
- @data ||= {}
61
- @data[version] ||= fetch_data(version:)
62
- end
63
-
64
- attr_reader :system_id
65
-
66
- private
67
-
68
- def get(path, params: nil)
69
- @connection.get(path, params:)
70
- end
71
-
72
- def fetch_data(version:)
73
- raise ArgumentError unless AVAILABLE_VERSIONS.include?(version)
74
- return unless system_id
75
-
76
- get("/#{version}/senec/systems/#{system_id}/dashboard")
77
- end
78
- end
79
- end
80
- end
@@ -1,69 +0,0 @@
1
- require_relative 'connection'
2
-
3
- # Model for the Senec technical data.
4
- #
5
- # Example use:
6
- #
7
- # connection = Senec::Cloud::Connection.new(username: '...', password: '...')
8
- #
9
- # # Get the data of a specific system:
10
- # TechnicalData[connection].find('123456')
11
- #
12
- # # Get the data of the default system:
13
- # TechnicalData[connection].first
14
- #
15
- module Senec
16
- module Cloud
17
- class TechnicalData
18
- class Finder
19
- def initialize(connection)
20
- @connection = connection
21
- end
22
- attr_reader :connection
23
-
24
- def find(system_id)
25
- TechnicalData.new(connection:, system_id:).tap(&:load_data)
26
- end
27
-
28
- def first
29
- find(connection.default_system_id)
30
- end
31
- end
32
-
33
- def self.[](connection)
34
- Finder.new(connection)
35
- end
36
-
37
- def initialize(connection: nil, system_id: nil, data: nil)
38
- raise ArgumentError unless connection.nil? ^ data.nil?
39
-
40
- @connection = connection
41
- @system_id = system_id
42
-
43
- # Useful for testing only
44
- @data = data
45
- end
46
-
47
- def load_data
48
- raise 'Data already present!' if @data
49
-
50
- @system_id ||= connection.default_system_id
51
- @data = fetch_data
52
- end
53
-
54
- attr_reader :system_id, :data
55
-
56
- private
57
-
58
- def get(path, params: nil)
59
- @connection.get(path, params:)
60
- end
61
-
62
- def fetch_data
63
- return unless system_id
64
-
65
- get("/v1/senec/systems/#{system_id}/technical-data")
66
- end
67
- end
68
- end
69
- end