senec 0.10.0 → 0.12.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: 527ddd13c38f45eca03b8318f29222d8f4f2fc1d3c34139f1f0642cb10a7db1a
4
- data.tar.gz: c277e0d2dd6f68ac0b02f77d36ff3b9dd0bee46206a902c189a1b715975d3c5c
3
+ metadata.gz: 30ce4b689a7e76c8c2a3c9a1f8657d24aadbcaa981c2e4d6892b5d65c490bd32
4
+ data.tar.gz: 5d353f3b783dd597fa0481efbcd117461f15bd2ffe174005c00e161b39aee458
5
5
  SHA512:
6
- metadata.gz: e2013e5206c4ef197828440d7fc3549cfce2b4254b0e22c936edf288e00a7a19e4cec246b9a49f4b19c1979104603bb5f56e7fddf70261153f7c933b94f1c668
7
- data.tar.gz: 6d0f15867763036a3edead7450fcfd8a27a3ea5d3a278cbb9960d7225e7d5226bd21d003d83417aa3eee8908f82ae8036437f7aec81f224dd3f085dd0f2623fe
6
+ metadata.gz: 6621fc5b71d198e428a6b51db406c1e3c5e0e75248d4767c5f9d91fa77235fa2d8866b3cc978adc5fce63c166ca01257b3f904af4d684c0f170bc210011c537b
7
+ data.tar.gz: 93f57a2a8c265c07670e0c99a8a0b492defa4d3e201c13dd9928d1abbfbb3860fc9d91602b0447b5c6025174a14bfd200fe841ab6e8d687b924a57e4e3bf7ef8
@@ -9,7 +9,7 @@ jobs:
9
9
  strategy:
10
10
  fail-fast: false
11
11
  matrix:
12
- ruby: ['3.0', '3.1', '3.2']
12
+ ruby: ['3.2']
13
13
 
14
14
  steps:
15
15
  - name: Checkout the code
data/.rubocop.yml CHANGED
@@ -4,7 +4,7 @@ require:
4
4
  - rubocop-rake
5
5
 
6
6
  AllCops:
7
- TargetRubyVersion: 3.0
7
+ TargetRubyVersion: 3.2
8
8
  NewCops: enable
9
9
 
10
10
  Style/Documentation:
data/Gemfile CHANGED
@@ -23,6 +23,3 @@ gem 'rubocop-rake'
23
23
 
24
24
  # Record your test suite's HTTP interactions and replay them during future test runs for fast, deterministic, accurate tests. (https://relishapp.com/vcr/vcr/docs)
25
25
  gem 'vcr'
26
-
27
- # Library for stubbing HTTP requests in Ruby. (https://github.com/bblimke/webmock)
28
- gem 'webmock'
data/README.md CHANGED
@@ -23,8 +23,8 @@ $ gem install senec
23
23
  ```ruby
24
24
  require 'senec'
25
25
 
26
- senec_ip = '10.0.1.99'
27
- request = Senec::Request.new host: senec_ip
26
+ connection = Senec::Connection.new(host: '192.168.178.123', schema: 'https')
27
+ request = Senec::Request.new(connection:)
28
28
 
29
29
  puts "PV production: #{request.inverter_power} W"
30
30
  puts "House power consumption: #{request.house_power} W"
@@ -39,7 +39,7 @@ puts "\n"
39
39
  puts "Wallbox charge power: [ #{request.wallbox_charge_power.join(',')} ] W"
40
40
  puts "\n"
41
41
  puts "Grid power: #{request.grid_power} W"
42
- puts "Current state of the system: #{request.current_state}"
42
+ puts "Current state of the system: #{request.current_state_code}"
43
43
  puts "Measure time: #{Time.at request.measure_time}"
44
44
 
45
45
  # Example result:
@@ -61,17 +61,19 @@ puts "Measure time: #{Time.at request.measure_time}"
61
61
  # Measure time: 2021-10-06 17:50:22 +0200
62
62
  ```
63
63
 
64
- To get the state name (in German) instead of just the number:
64
+ To get the state name (in English, German or Italian) instead of just the number:
65
65
 
66
66
  ```ruby
67
- state_names = Senec::State.new(host: senec_ip).names
68
- request = Senec::Request.new host: senec_ip, state_names: state_names
67
+ # Get a Hash with all available state names:
68
+ state_names = Senec::State.new(connection:).names(language: :de) # or :en or :it
69
+ # Use this hash for the number => string mapping:
70
+ request = Senec::Request.new(connection:, state_names:)
69
71
 
70
72
  puts request.current_state_name
71
73
  # => "LADEN"
72
74
  ```
73
75
 
74
- The state names are extracted on-the-fly from the JavaScript source code returned by the SENEC web interface.
76
+ The state names are extracted from the JavaScript source code returned by the SENEC web interface.
75
77
 
76
78
  ## Development
77
79
 
@@ -0,0 +1,30 @@
1
+ require 'faraday'
2
+ require 'faraday/net_http_persistent'
3
+ require 'faraday-request-timer'
4
+ require 'forwardable'
5
+
6
+ module Senec
7
+ class Connection
8
+ def initialize(host:, schema: 'http')
9
+ @url = "#{schema}://#{host}"
10
+ end
11
+
12
+ extend Forwardable
13
+ def_delegators :faraday, :get, :post
14
+
15
+ private
16
+
17
+ def faraday
18
+ @faraday ||= Faraday.new @url,
19
+ ssl: { verify: false },
20
+ headers: {
21
+ 'Connection' => 'keep-alive'
22
+ } do |f|
23
+ f.request :timer
24
+ f.adapter :net_http_persistent, pool_size: 5 do |http|
25
+ http.idle_timeout = 30
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
data/lib/senec/request.rb CHANGED
@@ -1,16 +1,14 @@
1
- require 'httparty'
2
1
  require 'senec/value'
3
2
  require 'senec/constants'
4
3
 
5
4
  module Senec
6
5
  class Request
7
- def initialize(host:, schema: 'http', state_names: nil)
8
- @host = host
9
- @schema = schema
6
+ def initialize(connection:, state_names: nil)
7
+ @connection = connection
10
8
  @state_names = state_names
11
9
  end
12
10
 
13
- attr_reader :host, :schema, :state_names
11
+ attr_reader :connection, :state_names
14
12
 
15
13
  def house_power
16
14
  get('ENERGY', 'GUI_HOUSE_POW')
@@ -56,14 +54,14 @@ module Senec
56
54
  get('WIZARD', 'APPLICATION_VERSION')
57
55
  end
58
56
 
59
- def current_state
57
+ def current_state_code
60
58
  get('ENERGY', 'STAT_STATE')
61
59
  end
62
60
 
63
61
  def current_state_name
64
62
  throw RuntimeError, 'No state names provided!' unless state_names
65
63
 
66
- state_names[current_state]
64
+ state_names[current_state_code]
67
65
  end
68
66
 
69
67
  def measure_time
@@ -73,10 +71,16 @@ module Senec
73
71
  web_time - (utc_offset * 60)
74
72
  end
75
73
 
74
+ def response_duration
75
+ raw_response.env[:duration]
76
+ end
77
+
76
78
  private
77
79
 
78
80
  def get(*keys)
79
- value = response.dig(*keys)
81
+ return unless parsed_response
82
+
83
+ value = parsed_response.dig(*keys)
80
84
 
81
85
  if value.is_a?(Array)
82
86
  value.map do |v|
@@ -91,24 +95,32 @@ module Senec
91
95
  raise Senec::Error, "Decoding failed for #{keys.join('.')}: #{e.message}"
92
96
  end
93
97
 
94
- def response
95
- @response ||= begin
96
- res = HTTParty.post(
97
- url,
98
- body: JSON.generate(Senec::BASIC_REQUEST),
99
- headers: {
100
- 'Content-Type' => 'application/x-www-form-urlencoded; charset=UTF-8'
101
- },
102
- verify: false
103
- )
104
- raise Senec::Error, res.message.to_s unless res.success?
98
+ def parsed_response
99
+ @parsed_response ||= JSON.parse(raw_response.body)
100
+ end
101
+
102
+ def raw_response
103
+ @raw_response ||= begin
104
+ response = connection.post(url, request_body, request_header)
105
+ raise Senec::Error, response.status unless response.success?
105
106
 
106
- res.parsed_response
107
+ response
107
108
  end
108
109
  end
109
110
 
110
111
  def url
111
- "#{schema}://#{host}/lala.cgi"
112
+ '/lala.cgi'
113
+ end
114
+
115
+ def request_body
116
+ JSON.generate(Senec::BASIC_REQUEST)
117
+ end
118
+
119
+ def request_header
120
+ {
121
+ 'Content-Type' => 'application/x-www-form-urlencoded; charset=UTF-8',
122
+ 'Accept' => 'application/json, text/javascript, */*; q=0.01'
123
+ }
112
124
  end
113
125
  end
114
126
  end
data/lib/senec/state.rb CHANGED
@@ -1,13 +1,10 @@
1
- require 'httparty'
2
-
3
1
  module Senec
4
2
  class State
5
- def initialize(host:, schema: 'http')
6
- @host = host
7
- @schema = schema
3
+ def initialize(connection:)
4
+ @connection = connection
8
5
  end
9
6
 
10
- attr_reader :host, :schema
7
+ attr_reader :connection
11
8
 
12
9
  # Extract state names from JavaScript file, which is formatted like this:
13
10
  #
@@ -16,8 +13,8 @@ module Senec
16
13
  # 1: "SECOND STATE",
17
14
  # ...
18
15
  # };
19
- def names
20
- response.match(FILE_REGEX)[0].split("\n").each_with_object({}) do |line, hash|
16
+ def names(language: :de)
17
+ response(language:).match(FILE_REGEX)[0].split("\n").each_with_object({}) do |line, hash|
21
18
  key, value = line.match(LINE_REGEX)&.captures
22
19
  next unless key && value
23
20
 
@@ -30,18 +27,25 @@ module Senec
30
27
  FILE_REGEX = /var system_state_name = \{(.*?)\};/m
31
28
  LINE_REGEX = /(\d+)\s*:\s*"(.*)"/
32
29
 
33
- def response
34
- @response ||= begin
35
- res = HTTParty.get url, verify: false
36
- raise Senec::Error, res.message unless res.success?
30
+ def response(language:)
31
+ res = connection.get url(language:)
32
+ raise Senec::Error, res.message unless res.success?
37
33
 
38
- res.body
39
- end
34
+ res.body
40
35
  end
41
36
 
42
- # Use the JavaScript file with German names from the SENEC web interface
43
- def url
44
- "#{schema}://#{host}/js/DE-de.js"
37
+ # Use the JavaScript file containing English/German/Italian names from the SENEC web interface
38
+ def url(language:)
39
+ case language
40
+ when :en
41
+ '/js/EN-en.js'
42
+ when :de
43
+ '/js/DE-de.js'
44
+ when :it
45
+ '/js/IT-it.js'
46
+ else
47
+ raise Senec::Error, "Language #{language} not supported"
48
+ end
45
49
  end
46
50
  end
47
51
  end
data/lib/senec/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Senec
2
- VERSION = '0.10.0'.freeze
2
+ VERSION = '0.12.0'.freeze
3
3
  end
data/lib/senec.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require 'senec/version'
2
+ require 'senec/connection'
2
3
  require 'senec/state'
3
4
  require 'senec/request'
4
5
 
data/senec.gemspec CHANGED
@@ -10,8 +10,10 @@ Gem::Specification.new do |spec|
10
10
  spec.description = 'Access your local SENEC Solar Battery Storage System'
11
11
  spec.homepage = 'https://github.com/solectrus/senec'
12
12
  spec.license = 'MIT'
13
- spec.required_ruby_version = Gem::Requirement.new('>= 3.0.0')
14
- spec.add_runtime_dependency 'httparty'
13
+ spec.required_ruby_version = Gem::Requirement.new('>= 3.2.0')
14
+ spec.add_runtime_dependency 'faraday'
15
+ spec.add_runtime_dependency 'faraday-net_http_persistent'
16
+ spec.add_runtime_dependency 'faraday-request-timer'
15
17
 
16
18
  spec.metadata['homepage_uri'] = spec.homepage
17
19
  spec.metadata['source_code_uri'] = 'https://github.com/solectrus/senec'
metadata CHANGED
@@ -1,17 +1,45 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: senec
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.0
4
+ version: 0.12.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Georg Ledermann
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-08-27 00:00:00.000000000 Z
11
+ date: 2023-09-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: httparty
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: faraday-net_http_persistent
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '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'
41
+ - !ruby/object:Gem::Dependency
42
+ name: faraday-request-timer
15
43
  requirement: !ruby/object:Gem::Requirement
16
44
  requirements:
17
45
  - - ">="
@@ -44,6 +72,7 @@ files:
44
72
  - bin/console
45
73
  - bin/setup
46
74
  - lib/senec.rb
75
+ - lib/senec/connection.rb
47
76
  - lib/senec/constants.rb
48
77
  - lib/senec/request.rb
49
78
  - lib/senec/state.rb
@@ -66,7 +95,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
66
95
  requirements:
67
96
  - - ">="
68
97
  - !ruby/object:Gem::Version
69
- version: 3.0.0
98
+ version: 3.2.0
70
99
  required_rubygems_version: !ruby/object:Gem::Requirement
71
100
  requirements:
72
101
  - - ">="