atrea_control 2.2.0 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5c955050ce44ade41eca756597796e8cd3fe8f58c4d7444140a1e648e2d375a5
4
- data.tar.gz: f451c587d86fb14ef2089186da37366801006d3ea2aacfbffd010469ab16366b
3
+ metadata.gz: 919ab4f4ed1dde112816e58cecfb4ffc393cb539cecf81796a2490219683c75d
4
+ data.tar.gz: 7b450714f08130ad30ad565c5ce04b22b29435c43cd8230dbf10103a04c9e624
5
5
  SHA512:
6
- metadata.gz: c6b598e0592c42d97dfada40c27585b93e19752d7c5221f5c44409aaedb214711c51e493fb81bfc65ca37c6bbcb87811c5dc73b13465378fabd42678fe48683d
7
- data.tar.gz: 3c137f8ecd8ccb7c1b6908fe4a6f8397fcb19b3dd7f887497c7226e086ef2646e286d0a2f6639860640e65eee9347a77ae57b354e2f612a5ccc2a9c13c6d1ab2
6
+ metadata.gz: 360fc2c895cc21dabffd4450a5013899263077b7a9f5c968c7046584728e457f795e8a159dc714021ac2dfaed2b5fe3792debd67c88c52810144d83bea792cff
7
+ data.tar.gz: bfdd992e729adccf960aee9d26e9088ef9fe7beb20f1067396099248659c187e079f303504e04fefb7bdac9dee0dd0249f01c053b39966cef67f55c2da2ada69
@@ -1,17 +1,19 @@
1
1
  name: Ruby
2
2
 
3
- on: [push,pull_request]
3
+ on: [push, pull_request]
4
4
 
5
5
  jobs:
6
6
  spec:
7
7
  runs-on: ubuntu-latest
8
+ strategy:
9
+ matrix:
10
+ ruby-version: [3.2, 3.3, 3]
8
11
  steps:
9
12
  - uses: actions/checkout@v4
10
13
  - name: Set up Ruby
11
14
  uses: ruby/setup-ruby@v1
12
15
  with:
13
- ruby-version: 3.2.2
16
+ ruby-version: ${{ matrix.ruby-version }}
14
17
  bundler-cache: true
15
- - uses: browser-actions/setup-firefox@latest
16
18
  - name: Run tests
17
- run: bundle exec rspec
19
+ run: bundle exec rspec
data/.gitignore CHANGED
@@ -11,3 +11,4 @@
11
11
 
12
12
  # rspec failure tracking
13
13
  .rspec_status
14
+ .env
data/.rubocop.yml CHANGED
@@ -5,7 +5,7 @@ require:
5
5
  AllCops:
6
6
  NewCops: enable
7
7
  SuggestExtensions: false
8
- TargetRubyVersion: 3.2
8
+ TargetRubyVersion: 3.3
9
9
 
10
10
  Style/StringLiterals:
11
11
  Enabled: true
data/.rubocop_todo.yml CHANGED
@@ -1,17 +1,24 @@
1
1
  # This configuration was generated by
2
2
  # `rubocop --auto-gen-config`
3
- # on 2023-03-01 20:32:36 UTC using RuboCop version 1.47.0.
3
+ # on 2025-01-24 16:50:34 UTC using RuboCop version 1.70.0.
4
4
  # The point is for the user to remove these configuration records
5
5
  # one by one as the offenses are removed from the code base.
6
6
  # Note that changes in the inspected code, or installation of new
7
7
  # versions of RuboCop, may require this file to be generated again.
8
8
 
9
- # Offense count: 3
9
+ # Offense count: 1
10
+ # Configuration parameters: Severity, Include.
11
+ # Include: **/*.gemspec
12
+ Gemspec/RequiredRubyVersion:
13
+ Exclude:
14
+ - 'atrea_control.gemspec'
15
+
16
+ # Offense count: 5
10
17
  # Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes.
11
18
  Metrics/AbcSize:
12
19
  Max: 34
13
20
 
14
- # Offense count: 2
21
+ # Offense count: 3
15
22
  # Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns.
16
23
  Metrics/MethodLength:
17
24
  Max: 21
@@ -28,28 +35,30 @@ RSpec/ExpectInHook:
28
35
  Exclude:
29
36
  - 'spec/atrea_control/duplex/unit_spec.rb'
30
37
 
31
- # Offense count: 7
32
- # Configuration parameters: EnforcedStyle.
38
+ # Offense count: 4
39
+ # Configuration parameters: .
33
40
  # SupportedStyles: have_received, receive
34
41
  RSpec/MessageSpies:
35
- Exclude:
36
- - 'spec/atrea_control/duplex/login_spec.rb'
37
- - 'spec/atrea_control/duplex/unit_spec.rb'
42
+ EnforcedStyle: receive
38
43
 
39
- # Offense count: 2
44
+ # Offense count: 1
40
45
  RSpec/MultipleExpectations:
41
46
  Max: 3
42
47
 
43
- # Offense count: 3
48
+ # Offense count: 4
49
+ # This cop supports unsafe autocorrection (--autocorrect-all).
50
+ RSpec/ReceiveMessages:
51
+ Exclude:
52
+ - 'spec/atrea_control/duplex/unit_spec.rb'
53
+
54
+ # Offense count: 1
44
55
  RSpec/StubbedMock:
45
56
  Exclude:
46
- - 'spec/atrea_control/duplex/login_spec.rb'
47
57
  - 'spec/atrea_control/duplex/unit_spec.rb'
48
58
 
49
- # Offense count: 6
59
+ # Offense count: 9
50
60
  RSpec/SubjectStub:
51
61
  Exclude:
52
- - 'spec/atrea_control/duplex/login_spec.rb'
53
62
  - 'spec/atrea_control/duplex/unit_spec.rb'
54
63
  - 'spec/atrea_control/duplex/user_ctrl_spec.rb'
55
64
 
@@ -57,7 +66,6 @@ RSpec/SubjectStub:
57
66
  # Configuration parameters: IgnoreNameless, IgnoreSymbolicNames.
58
67
  RSpec/VerifiedDoubles:
59
68
  Exclude:
60
- - 'spec/atrea_control/duplex/login_spec.rb'
61
69
  - 'spec/atrea_control/duplex/unit_spec.rb'
62
70
  - 'spec/atrea_control/duplex/user_ctrl_spec.rb'
63
71
 
@@ -66,7 +74,7 @@ Security/Eval:
66
74
  Exclude:
67
75
  - 'lib/atrea_control/duplex/user_ctrl.rb'
68
76
 
69
- # Offense count: 2
77
+ # Offense count: 3
70
78
  # Configuration parameters: AllowedConstants.
71
79
  Style/Documentation:
72
80
  Exclude:
@@ -74,3 +82,10 @@ Style/Documentation:
74
82
  - 'test/**/*'
75
83
  - 'lib/atrea_control.rb'
76
84
  - 'lib/atrea_control/logger.rb'
85
+
86
+ # Offense count: 9
87
+ # This cop supports safe autocorrection (--autocorrect).
88
+ # Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, AllowedPatterns, SplitStrings.
89
+ # URISchemes: http, https
90
+ Layout/LineLength:
91
+ Max: 238
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 3.2.2
1
+ 3.3.6
data/CHANGELOG.md CHANGED
@@ -1,4 +1,19 @@
1
1
  ## [Unreleased]
2
+ ## [3.0.0] - 2025-01-25
3
+ ### Removed
4
+ - selenium-based login procedure
5
+ ### Added
6
+ - token / phpsessionid-based login in background
7
+ - "session" validity check & expiration (exception)
8
+ ### Changed
9
+ - ruby version 3.3+
10
+ -
11
+ ## [2.2.0] - 2024-10-20
12
+ ### Added
13
+ - timestamp from atrea server
14
+ ### Changed
15
+ - upgrade dependencies
16
+ - upgrade ruby version
2
17
 
3
18
  ## [2.2.0] - 2023-10-09
4
19
  ### Changed
data/Gemfile CHANGED
@@ -9,7 +9,7 @@ gem "pry"
9
9
  gem "rake", "~> 13.0"
10
10
  gem "rspec", "~> 3.10"
11
11
  gem "rubocop", "~> 1.7", require: false
12
- gem "rubocop-rspec", "~> 2.4", require: false
12
+ gem "rubocop-rspec", "~> 3.1", require: false
13
13
  group :test do
14
14
  gem "simplecov", require: false
15
15
  gem "webmock", "~> 3.14"
data/Gemfile.lock CHANGED
@@ -1,123 +1,111 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- atrea_control (2.2.0)
4
+ atrea_control (3.0.0)
5
5
  i18n (~> 1.14)
6
6
  nokogiri (~> 1.15)
7
7
  rest-client (~> 2.1)
8
- selenium-webdriver (~> 4.13.1)
9
8
 
10
9
  GEM
11
10
  remote: https://rubygems.org/
12
11
  specs:
13
- addressable (2.8.5)
14
- public_suffix (>= 2.0.2, < 6.0)
12
+ addressable (2.8.7)
13
+ public_suffix (>= 2.0.2, < 7.0)
15
14
  ast (2.4.2)
16
- base64 (0.1.1)
15
+ bigdecimal (3.1.9)
17
16
  coderay (1.1.3)
18
- concurrent-ruby (1.2.2)
19
- crack (0.4.5)
17
+ concurrent-ruby (1.3.5)
18
+ crack (1.0.0)
19
+ bigdecimal
20
20
  rexml
21
- diff-lcs (1.5.0)
22
- docile (1.4.0)
23
- domain_name (0.5.20190701)
24
- unf (>= 0.0.5, < 1.0.0)
25
- hashdiff (1.0.1)
21
+ diff-lcs (1.5.1)
22
+ docile (1.4.1)
23
+ domain_name (0.6.20240107)
24
+ hashdiff (1.1.2)
26
25
  http-accept (1.7.0)
27
- http-cookie (1.0.5)
26
+ http-cookie (1.0.8)
28
27
  domain_name (~> 0.5)
29
- i18n (1.14.1)
28
+ i18n (1.14.7)
30
29
  concurrent-ruby (~> 1.0)
31
- json (2.6.3)
30
+ json (2.9.1)
32
31
  language_server-protocol (3.17.0.3)
33
- method_source (1.0.0)
34
- mime-types (3.5.1)
32
+ logger (1.6.5)
33
+ method_source (1.1.0)
34
+ mime-types (3.6.0)
35
+ logger
35
36
  mime-types-data (~> 3.2015)
36
- mime-types-data (3.2023.1003)
37
+ mime-types-data (3.2025.0107)
37
38
  netrc (0.11.0)
38
- nokogiri (1.15.4-arm64-darwin)
39
+ nokogiri (1.18.2-arm64-darwin)
39
40
  racc (~> 1.4)
40
- nokogiri (1.15.4-x86_64-darwin)
41
+ nokogiri (1.18.2-x86_64-darwin)
41
42
  racc (~> 1.4)
42
- nokogiri (1.15.4-x86_64-linux)
43
+ nokogiri (1.18.2-x86_64-linux-gnu)
43
44
  racc (~> 1.4)
44
- parallel (1.23.0)
45
- parser (3.2.2.4)
45
+ parallel (1.26.3)
46
+ parser (3.3.7.0)
46
47
  ast (~> 2.4.1)
47
48
  racc
48
- pry (0.14.2)
49
+ pry (0.15.2)
49
50
  coderay (~> 1.1)
50
51
  method_source (~> 1.0)
51
- public_suffix (5.0.3)
52
- racc (1.7.1)
52
+ public_suffix (6.0.1)
53
+ racc (1.8.1)
53
54
  rainbow (3.1.1)
54
- rake (13.0.6)
55
- regexp_parser (2.8.1)
55
+ rake (13.2.1)
56
+ regexp_parser (2.10.0)
56
57
  rest-client (2.1.0)
57
58
  http-accept (>= 1.7.0, < 2.0)
58
59
  http-cookie (>= 1.0.2, < 2.0)
59
60
  mime-types (>= 1.16, < 4.0)
60
61
  netrc (~> 0.8)
61
- rexml (3.2.6)
62
- rspec (3.12.0)
63
- rspec-core (~> 3.12.0)
64
- rspec-expectations (~> 3.12.0)
65
- rspec-mocks (~> 3.12.0)
66
- rspec-core (3.12.2)
67
- rspec-support (~> 3.12.0)
68
- rspec-expectations (3.12.3)
62
+ rexml (3.4.0)
63
+ rspec (3.13.0)
64
+ rspec-core (~> 3.13.0)
65
+ rspec-expectations (~> 3.13.0)
66
+ rspec-mocks (~> 3.13.0)
67
+ rspec-core (3.13.2)
68
+ rspec-support (~> 3.13.0)
69
+ rspec-expectations (3.13.3)
69
70
  diff-lcs (>= 1.2.0, < 2.0)
70
- rspec-support (~> 3.12.0)
71
- rspec-mocks (3.12.6)
71
+ rspec-support (~> 3.13.0)
72
+ rspec-mocks (3.13.2)
72
73
  diff-lcs (>= 1.2.0, < 2.0)
73
- rspec-support (~> 3.12.0)
74
- rspec-support (3.12.1)
75
- rubocop (1.56.4)
76
- base64 (~> 0.1.1)
74
+ rspec-support (~> 3.13.0)
75
+ rspec-support (3.13.2)
76
+ rubocop (1.70.0)
77
77
  json (~> 2.3)
78
78
  language_server-protocol (>= 3.17.0)
79
79
  parallel (~> 1.10)
80
- parser (>= 3.2.2.3)
80
+ parser (>= 3.3.0.2)
81
81
  rainbow (>= 2.2.2, < 4.0)
82
- regexp_parser (>= 1.8, < 3.0)
83
- rexml (>= 3.2.5, < 4.0)
84
- rubocop-ast (>= 1.28.1, < 2.0)
82
+ regexp_parser (>= 2.9.3, < 3.0)
83
+ rubocop-ast (>= 1.36.2, < 2.0)
85
84
  ruby-progressbar (~> 1.7)
86
- unicode-display_width (>= 2.4.0, < 3.0)
87
- rubocop-ast (1.29.0)
88
- parser (>= 3.2.1.0)
89
- rubocop-capybara (2.19.0)
90
- rubocop (~> 1.41)
91
- rubocop-factory_bot (2.24.0)
92
- rubocop (~> 1.33)
93
- rubocop-rspec (2.24.1)
94
- rubocop (~> 1.33)
95
- rubocop-capybara (~> 2.17)
96
- rubocop-factory_bot (~> 2.22)
85
+ unicode-display_width (>= 2.4.0, < 4.0)
86
+ rubocop-ast (1.37.0)
87
+ parser (>= 3.3.1.0)
88
+ rubocop-rspec (3.4.0)
89
+ rubocop (~> 1.61)
97
90
  ruby-progressbar (1.13.0)
98
- rubyzip (2.3.2)
99
- selenium-webdriver (4.13.1)
100
- rexml (~> 3.2, >= 3.2.5)
101
- rubyzip (>= 1.2.2, < 3.0)
102
- websocket (~> 1.0)
103
91
  simplecov (0.22.0)
104
92
  docile (~> 1.1)
105
93
  simplecov-html (~> 0.11)
106
94
  simplecov_json_formatter (~> 0.1)
107
- simplecov-html (0.12.3)
95
+ simplecov-html (0.13.1)
108
96
  simplecov_json_formatter (0.1.4)
109
- unf (0.1.4)
110
- unf_ext
111
- unf_ext (0.0.8.2)
112
- unicode-display_width (2.5.0)
113
- webmock (3.19.1)
97
+ unicode-display_width (3.1.4)
98
+ unicode-emoji (~> 4.0, >= 4.0.4)
99
+ unicode-emoji (4.0.4)
100
+ webmock (3.24.0)
114
101
  addressable (>= 2.8.0)
115
102
  crack (>= 0.3.2)
116
103
  hashdiff (>= 0.4.0, < 2.0.0)
117
- websocket (1.2.10)
118
104
 
119
105
  PLATFORMS
120
106
  arm64-darwin-22
107
+ arm64-darwin-23
108
+ arm64-darwin-24
121
109
  x86_64-darwin-20
122
110
  x86_64-linux
123
111
 
@@ -127,9 +115,9 @@ DEPENDENCIES
127
115
  rake (~> 13.0)
128
116
  rspec (~> 3.10)
129
117
  rubocop (~> 1.7)
130
- rubocop-rspec (~> 2.4)
118
+ rubocop-rspec (~> 3.1)
131
119
  simplecov
132
120
  webmock (~> 3.14)
133
121
 
134
122
  BUNDLED WITH
135
- 2.4.16
123
+ 2.6.3
data/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # atrea_control
2
2
  Ventilation systems by https://www.atrea.eu are build with web UI portal - but this portal did not provide any API interface...
3
3
 
4
- This gem provide simple DSL by parsing content of https://control.atrea.eu with selenium webdriver.
4
+ This gem provide way how to connect to portal and obtain data from unit as API.
5
5
 
6
6
  ## Highlights
7
7
 
@@ -19,25 +19,38 @@ This gem provide simple DSL by parsing content of https://control.atrea.eu with
19
19
  Add this line to your application's Gemfile:
20
20
 
21
21
  ```ruby
22
- gem 'atrea_control'
22
+ gem "atrea_control"
23
23
  ```
24
24
 
25
25
  And then execute:
26
+ ```bash
27
+ bundle install
28
+ ```
26
29
 
27
- $ bundle install
30
+ Or
31
+ ```bash
32
+ bundle add atrea_control
33
+ ```
28
34
 
29
35
  Or install it yourself as:
30
36
 
31
- $ gem install atrea_control
37
+ ```bash
38
+ gem install atrea_control
39
+ ```
32
40
 
33
41
  ## Usage
34
42
 
35
43
  At the begin you need obtain `user_id`, `unit_id` and `sid` (auth token). For this use "Login"
44
+
45
+ * `user_id` is atrea internal ID of user account
46
+ * `unit_id` is atrea `ident` - identification number of airflow unit (ventilation system) - 10 digits
47
+ * `sid` is session ID - auth token, valid for logged session. Its validity is unknown
48
+
36
49
  ```ruby
37
50
  tokens = AtreaControl::Duplex::Login.user_tokens login: "myhome", password: "sup3r-S3CR3T-kocicka"
38
51
  tokens # => { user_id: "1234", unit_id: "85425324672", sid: 4012 }
39
52
  ```
40
- I recommend to store then somewhere...
53
+ I recommend to store then somewhere...
41
54
  Then you can call Unit for data...
42
55
 
43
56
  Example usage:
@@ -46,6 +59,7 @@ control = AtreaControl::Duplex::Unit.new user_id: "1234", unit_id: "85425324672"
46
59
  control.values # => { current_power: 88.0, current_mode: "CO2" }
47
60
  control.power # => 88.0
48
61
  ```
62
+
49
63
  ### Dig deeper
50
64
  `AtreaControl::Duplex::Unit` expect optional argument `user_ctrl` which should be object respond to
51
65
 
@@ -56,36 +70,12 @@ control.power # => 88.0
56
70
 
57
71
  __Please check [lib/atrea_control/duplex/user_ctrl.rb](./lib/atrea_control/duplex/user_ctrl.rb) for more details !__
58
72
 
59
- ## Development / TODO
60
- Login is currently done by selenium - fill login form.
61
- I found that Atre submit form to BE, generate some "empty" HTML and JS which onLoad start doing request to queue for "login".
62
-
63
- Re-login user, add login procedure into queue:
64
- ```bash
65
- curl -X POST -d "comm=config%2Flogin.cgi" "https://control.atrea.eu/apps/rd5Control/handle.php?action=unitLogin&user=XXXX&unit=NNNNNNN&table=userUnits&idPwd=YYYYYYY&NFP"
66
- ```
67
- Response is time in seconds when login will ready:
68
- ```xml
69
- <root><sended time="264"/></root>
70
- ```
71
- Based it su shown countdown ...
72
-
73
-
74
- Request for current queue status
75
- ```bash
76
- curl 'https://control.atrea.eu/apps/rd5Control/handle.php?Sync=1&action=unitQuery&query=loged&user=XXXX&unit=NNNNNNN'
77
- ```
78
- if queue is processed:
79
- ```xml
80
- <root><login uconn="16395889" sid="010101" ver="3001009"/></root>
81
- ```
82
- else
83
- ```xml
84
- <root><login uconn="16390480" sid="0"/></root>
85
- ```
73
+ This object is used to translate internal unit modes to user-friendly texts & translations.
86
74
 
87
- Goal is to obtain "SID".
75
+ I strong recommend to use `AtreaControl::Duplex::UserCtrl` object from "cache",
76
+ for optimize network traffic - because they are static data.
88
77
 
78
+ ## Development
89
79
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
90
80
 
91
81
  To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
@@ -11,7 +11,7 @@ Gem::Specification.new do |spec|
11
11
  spec.summary = "Get data control.atrea.eu"
12
12
  spec.description = "Read data from web controller of RD5 duplex by Atrea."
13
13
  spec.homepage = "https://github.com/luk4s/atrea_control"
14
- spec.required_ruby_version = Gem::Requirement.new("~> 3.2.2")
14
+ spec.required_ruby_version = Gem::Requirement.new("~> 3.2")
15
15
 
16
16
  spec.metadata["allowed_push_host"] = "https://rubygems.org"
17
17
 
@@ -39,5 +39,4 @@ Gem::Specification.new do |spec|
39
39
  spec.add_dependency "i18n", "~> 1.14"
40
40
  spec.add_dependency "nokogiri", "~> 1.15"
41
41
  spec.add_dependency "rest-client", "~> 2.1"
42
- spec.add_dependency "selenium-webdriver", "~> 4.13.1"
43
42
  end
data/bin/console CHANGED
@@ -8,8 +8,8 @@ require "atrea_control"
8
8
  # with your gem easier. You can also use a different console, if you like.
9
9
 
10
10
  # (If you use this, don't forget to add pry to your Gemfile!)
11
- # require "pry"
12
- # Pry.start
11
+ require "pry"
12
+ Pry.start
13
13
 
14
- require "irb"
15
- IRB.start(__FILE__)
14
+ # require "irb"
15
+ # IRB.start(__FILE__)
@@ -1,23 +1,19 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "digest"
3
+ require "nokogiri"
4
4
  require "rest-client"
5
- require "selenium-webdriver"
5
+ require "securerandom"
6
6
 
7
7
  module AtreaControl
8
8
  module Duplex
9
- # Process login into RD5 with selenium to get `sid` ( auth_token ) for direct API communication
9
+ # Process login into RD5 to get `sid` ( auth_token ) for direct API communication
10
10
  class Login
11
11
  include AtreaControl::Logger
12
12
 
13
13
  # @return [Hash] - user_id, unit_id, sid
14
14
  def self.user_tokens(login:, password:)
15
- i = new(login: login, password: password)
16
- tokens = i.user
17
-
18
- tokens
19
- ensure
20
- i.close
15
+ instance = new(login: login, password: password)
16
+ instance.call
21
17
  end
22
18
 
23
19
  # @param [String] login
@@ -26,101 +22,107 @@ module AtreaControl
26
22
  @login = login
27
23
  @password = password
28
24
  end
29
- #
30
- # def crypto_password
31
- # md5 = Digest::MD5.new
32
- # md5 << "\r\n"
33
- # md5 << @password
34
- # md5.hexdigest
35
- # end
36
- #
37
- # def token
38
- # RestClient.get "#{AtreaControl::Duplex::CONTROL_URI}/config/login.cgi", params: { magic: crypto_password }
39
- # end
40
25
 
41
- def user
42
- raise AtreaControl::Error, "Must be logged in" unless login
26
+ # Perform login procedure for retrieve `sid` (auth_token)
27
+ # @return [Hash] - user_id, unit_id, sid
28
+ # @raise [AtreaControl::Error] if login failed
29
+ def call
30
+ @sid = sid
31
+ if @sid == "0"
32
+ re_login = RestClient.post "#{AtreaControl::Duplex::CONTROL_URI}/apps/rd5Control/handle.php?action=unitLogin&user=#{user_id}&unit=#{unit_id}&table=userUnits&idPwd=#{unit[:iid]}&#{SecureRandom.hex(2)}&_ts=#{SecureRandom.hex(4)}",
33
+ { comm: "config/login.cgi?magic=" }, headers
34
+ time = Nokogiri::XML(re_login.body).at_xpath("//sended")["time"].to_i
35
+ logger.debug "Login in #{time} seconds..."
36
+ time.times do
37
+ @sid = sid
38
+ break if @sid != "0"
39
+
40
+ sleep 1
41
+ end
42
+ raise AtreaControl::Error, "Login failed" if @sid == "0"
43
+
44
+ logger.debug "Login complete !"
45
+ else
46
+ logger.debug "Login is not necessary ! SID: #{@sid}"
47
+ end
48
+ { user_id:, unit_id:, sid: @sid }
49
+ end
43
50
 
44
- logger.debug "refresh user data based on session"
45
- @user_id = driver.execute_script("return window._user")
46
- @unit_id = driver.execute_script("return window._unit")
47
- @auth_token = driver.execute_script("return window.user")&.[]("auth") # sid
51
+ private
48
52
 
49
- { user_id: @user_id, unit_id: @unit_id, sid: @auth_token }
50
- end
53
+ # @!group Login steps, order is important
51
54
 
52
- # @return [Selenium::WebDriver::Firefox::Driver]
53
- def driver
54
- return @driver if defined?(@driver)
55
+ # Retrieve user details from RD5 core.php?action=init
56
+ # @return [Hash] - user_id, name
57
+ def user
58
+ core_init = RestClient.get "#{AtreaControl::Duplex::CONTROL_URI}/core/core.php?action=init&_ts=#{SecureRandom.hex(4)}",
59
+ headers
60
+ client = Nokogiri::XML(core_init.body).at_xpath("//client")
61
+ user_id = client["id"]
62
+ name = client["name"]
63
+ logger.debug "User ID: #{user_id}, User Name: #{name}"
64
+
65
+ { user_id:, name: }
66
+ end
55
67
 
56
- # options = Selenium::WebDriver::Firefox::Options.new
57
- # options.headless! unless ENV["NO_HEADLESS"]
58
- # @driver ||= Selenium::WebDriver.for :firefox, capabilities: [options]
59
- options = Selenium::WebDriver::Firefox::Options.new
60
- options.add_argument "-headless" unless ENV["NO_HEADLESS"]
61
- @driver ||= Selenium::WebDriver::Firefox::Driver.new options: options
68
+ def user_id
69
+ @user_id ||= user[:user_id]
62
70
  end
63
71
 
64
- # Login into control
65
- def login
66
- return driver if @logged
67
-
68
- @login_in_progress = true
69
- logger.debug "start new login..."
70
- driver.get "#{AtreaControl::Duplex::CONTROL_URI}?action=logout"
71
- submit_login_form
72
- finish_login
73
- driver
74
- ensure
75
- @login_in_progress = false
72
+ # For some reason, this requests must be done before `unit_id` requested
73
+ def run_rd5_app
74
+ RestClient.post "#{AtreaControl::Duplex::CONTROL_URI}/core/core.php?Sync=1&action=run&object=app&lng=28&rVer=1&_ts=#{SecureRandom.hex(4)}",
75
+ { name: "rd5Control", path: "apps/rd5Control/" }, headers
76
+ RestClient.post "#{AtreaControl::Duplex::CONTROL_URI}/core/core.php?Sync=1&action=load&object=setting&_ts=#{SecureRandom.hex(4)}",
77
+ { path: "apps/rd5Control" }, headers
76
78
  end
77
79
 
78
- # Submit given credentials and proceed login
79
- def submit_login_form
80
- form = driver.find_element(id: "loginFrm")
81
- username = form.find_element(name: "username")
82
- username.send_keys @login
83
- password = form.find_element(name: "password")
84
- password.send_keys @password
85
- logger.debug "Submit login form..."
86
-
87
- submit = form.find_element(css: "input[type=submit]")
88
- submit.click
80
+ # Retrieve overview of RD5 unit
81
+ # @return [Hash] - unit_number (digit code/ID from list) and iid (unit salt?)
82
+ def unit
83
+ return @unit if @unit
84
+
85
+ # run_rd5_app
86
+ units_table = RestClient.get "#{AtreaControl::Duplex::CONTROL_URI}/_data/data.php?Sync=1&action=getdata&rH&rE&table=userUnits&ds=rd5&_ts=#{SecureRandom.hex(4)}",
87
+ headers
88
+ item = Nokogiri::XML(units_table.body).at_xpath("//i")
89
+ unit_number = item["unit"]
90
+ iid = item["id"]
91
+ @unit ||= { unit_number:, iid: }
89
92
  end
90
93
 
91
- # Retrieve dashboard URI from object tag and open it again
92
- def open_dashboard
93
- uri = driver.find_element(tag_name: "object").attribute "data"
94
- # Open "iframe" with atrea dashboard - it propagate window objects...
95
- driver.get uri
96
- logger.debug "login success"
97
- @logged = true
94
+ # With `unit_number` from `unit` method, get `unit_id` from RD5 unit records
95
+ # @return [String] - unit_id
96
+ def unit_id
97
+ return @unit_id if @unit_id
98
+
99
+ records = RestClient.get "#{AtreaControl::Duplex::CONTROL_URI}/_data/data.php?Sync=1&action=getrecord&id=#{unit[:unit_number]}&table=units&ds=rd5&_ts=#{SecureRandom.hex(4)}",
100
+ headers
101
+ @unit_id ||= Nokogiri::XML(records.body).at_xpath("//table/i")["ident"]
98
102
  end
99
103
 
100
- # quit selenium browser
101
- def close
102
- begin
103
- driver.quit
104
- rescue StandardError
105
- nil
106
- end
107
- logger.debug "driver closed & destroyed"
108
- ensure
109
- remove_instance_variable :@driver
104
+ def sid
105
+ data = RestClient.get "#{AtreaControl::Duplex::CONTROL_URI}/apps/rd5Control/handle.php?Sync=1&action=unitQuery&query=loged&user=#{user_id}&unit=#{unit_id}&#{SecureRandom.hex(2)}&_ts=#{SecureRandom.hex(4)}",
106
+ headers
107
+ logger.debug data.body
108
+ Nokogiri::XML(data.body).at_xpath("//login")["sid"]
110
109
  end
111
110
 
112
- private
111
+ # @!group Private methods
113
112
 
114
- def finish_login
115
- 30.times do |i|
116
- return true if open_dashboard
117
- rescue Selenium::WebDriver::Error::NoSuchElementError => e
118
- logger.debug e.message
119
- logger.debug "#{i + 1}/30 attempt for login..."
120
- sleep 10
113
+ # @return [String] session ID from PHP BE
114
+ def php_session_id
115
+ return @php_session_id if @php_session_id
116
+
117
+ payload = { username: @login, password: @password }
118
+ RestClient.post "#{AtreaControl::Duplex::CONTROL_URI}?action=login", payload do |response|
119
+ @php_session_id = response.cookies["PHPSESSID"]
121
120
  end
122
- File.write("/tmp/failed_login-#{@login}.html", driver.page_source)
123
- raise AtreaControl::Error, "unable to login"
121
+ @php_session_id
122
+ end
123
+
124
+ def headers
125
+ { cookies: { PHPSESSID: php_session_id }, "App-name": "rd5Control" }
124
126
  end
125
127
  end
126
128
  end
@@ -29,3 +29,4 @@ module AtreaControl
29
29
  end
30
30
  end
31
31
  end
32
+ # https://control.atrea.eu/comm/sw/unit.php?ver=003001022&_user=2113&_unit=126399332270040&auth=49852&_t=config/xml.xml&_X=Ti&_async=1
@@ -9,10 +9,10 @@ module AtreaControl
9
9
  attr_reader :current_mode, :current_power, :outdoor_temperature, :preheat_temperature, :input_temperature
10
10
  # @return [Boolean] preheating air is ON ?
11
11
  attr_reader :preheating
12
- # @return [DateTime] store time of last update
13
- attr_reader :valid_for
14
12
  # @return [UserCtrl]
15
13
  attr_reader :user_ctrl
14
+ # @return [Time, DateTime]
15
+ attr_writer :timestamp
16
16
 
17
17
  # @param [String, Integer] user_id
18
18
  # @param [String, Integer] unit_id
@@ -37,6 +37,10 @@ module AtreaControl
37
37
  current_power || values[:current_power]
38
38
  end
39
39
 
40
+ def timestamp
41
+ @timestamp ||= values[:timestamp]
42
+ end
43
+
40
44
  def preheating?
41
45
  preheating || values[:preheating]
42
46
  end
@@ -56,13 +60,15 @@ module AtreaControl
56
60
  end
57
61
 
58
62
  def parsed
59
- parser.values(read.body)
63
+ @parsed ||= parser.values(read.body)
60
64
  end
61
65
 
62
66
  def values
63
67
  parsed.each do |name, value|
64
68
  instance_variable_set :"@#{name}", value
65
69
  end
70
+ raise AtreaControl::SessionExpired unless valid?
71
+
66
72
  as_json
67
73
  end
68
74
 
@@ -74,7 +80,7 @@ module AtreaControl
74
80
  preheat_temperature: preheat_temperature,
75
81
  input_temperature: input_temperature,
76
82
  preheating: preheating,
77
- valid_for: valid_for,
83
+ timestamp: timestamp,
78
84
  }
79
85
  end
80
86
 
@@ -82,15 +88,29 @@ module AtreaControl
82
88
  values.to_json(*)
83
89
  end
84
90
 
85
- # Additional "parameters" for each sensors
86
- # @note its changed in time ?
91
+ # Expire cached data and fetch them again
92
+ # @return [Hash] new values
93
+ def refresh!
94
+ remove_instance_variable(:@parsed) if defined?(@parsed)
95
+ values
96
+ end
97
+
98
+ # Data are valid if timestamp within 15.minutes
99
+ def valid?
100
+ return false unless timestamp
101
+
102
+ timestamp > (Time.now - (15 * 60.0))
103
+ end
104
+
105
+ private
106
+
107
+ # Additional "parameters" for each sensor
108
+ # @note it's changed in time ?
87
109
  def params
88
110
  response = request.call(_t: "user/params.xml")
89
111
  Nokogiri::XML response.body
90
112
  end
91
113
 
92
- private
93
-
94
114
  def parser
95
115
  @parser ||= ::AtreaControl::SensorParser.new(@user_ctrl)
96
116
  end
@@ -33,7 +33,7 @@ module AtreaControl
33
33
 
34
34
  # Get and parse XML with user/unit configuration source
35
35
  def user_ctrl
36
- response = request.call(_t: "lang/userCtrl.xml")
36
+ response = request.call(_t: "lang/userCtrl.xml", _async: 1)
37
37
  Nokogiri::XML response.body
38
38
  end
39
39
 
@@ -4,7 +4,7 @@ module AtreaControl
4
4
  # Controller for +control.atrea.eu+
5
5
  module Duplex
6
6
  CONTROL_URI = "https://control.atrea.eu/"
7
- CONTROL_VERSION = "003001009"
7
+ CONTROL_VERSION = "003001022"
8
8
 
9
9
  autoload :Login, "atrea_control/duplex/login"
10
10
  autoload :Request, "atrea_control/duplex/request"
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "nokogiri"
4
+ require "time"
4
5
 
5
6
  module AtreaControl
6
7
  # Call RD5 unit ang get current sensors values
@@ -43,6 +44,8 @@ module AtreaControl
43
44
  preheating = %w[C10200 C10202 C10215 C10217].any? do |i|
44
45
  xml.xpath("//O[@I=\"#{i}\"]/@V").last&.value == "1"
45
46
  end
47
+ # @note timestamp seems to be localtime of creation of xml
48
+ parsed["timestamp"] = xml.xpath("//RD5WEB").attribute("t").to_s
46
49
  parsed["preheating"] = preheating
47
50
  parsed
48
51
  end
@@ -57,7 +60,7 @@ module AtreaControl
57
60
  "preheat_temperature" => values["preheat_temperature"].to_f / 10.0,
58
61
  "input_temperature" => values["input_temperature"].to_f / 10.0,
59
62
  "preheating" => values["preheating"],
60
- "valid_for" => Time.now,
63
+ "timestamp" => Time.strptime(values["timestamp"], "%Y-%m-%d %H:%M:%S"),
61
64
  }
62
65
  end
63
66
 
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
+ # :nocov:
2
3
 
3
4
  module AtreaControl
4
- VERSION = "2.2.0"
5
+ VERSION = "3.0.0"
5
6
  end
data/lib/atrea_control.rb CHANGED
@@ -7,6 +7,12 @@ require "yaml"
7
7
  module AtreaControl
8
8
  class Error < StandardError; end
9
9
 
10
+ class SessionExpired < Error
11
+ def message
12
+ "Session expired. Please perform login again."
13
+ end
14
+ end
15
+
10
16
  autoload :Duplex, "atrea_control/duplex"
11
17
  autoload :Logger, "atrea_control/logger"
12
18
  autoload :SensorParser, "atrea_control/sensor_parser"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: atrea_control
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.0
4
+ version: 3.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lukáš Pokorný
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-10-09 00:00:00.000000000 Z
11
+ date: 2025-01-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: i18n
@@ -52,20 +52,6 @@ dependencies:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: '2.1'
55
- - !ruby/object:Gem::Dependency
56
- name: selenium-webdriver
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - "~>"
60
- - !ruby/object:Gem::Version
61
- version: 4.13.1
62
- type: :runtime
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - "~>"
67
- - !ruby/object:Gem::Version
68
- version: 4.13.1
69
55
  description: Read data from web controller of RD5 duplex by Atrea.
70
56
  email:
71
57
  - pokorny@luk4s.cz
@@ -112,14 +98,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
112
98
  requirements:
113
99
  - - "~>"
114
100
  - !ruby/object:Gem::Version
115
- version: 3.2.2
101
+ version: '3.2'
116
102
  required_rubygems_version: !ruby/object:Gem::Requirement
117
103
  requirements:
118
104
  - - ">="
119
105
  - !ruby/object:Gem::Version
120
106
  version: '0'
121
107
  requirements: []
122
- rubygems_version: 3.4.16
108
+ rubygems_version: 3.5.22
123
109
  signing_key:
124
110
  specification_version: 4
125
111
  summary: Get data control.atrea.eu