senec 0.10.0 → 0.11.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 527ddd13c38f45eca03b8318f29222d8f4f2fc1d3c34139f1f0642cb10a7db1a
4
- data.tar.gz: c277e0d2dd6f68ac0b02f77d36ff3b9dd0bee46206a902c189a1b715975d3c5c
3
+ metadata.gz: 0d619a385d96958f3d69b8486977b64ec6c0d758dff3179138714ba22f7915d5
4
+ data.tar.gz: 52991e9de034ebeda649ebf48f138d9f3dc71d69d005e25d8e45bcac2bd79804
5
5
  SHA512:
6
- metadata.gz: e2013e5206c4ef197828440d7fc3549cfce2b4254b0e22c936edf288e00a7a19e4cec246b9a49f4b19c1979104603bb5f56e7fddf70261153f7c933b94f1c668
7
- data.tar.gz: 6d0f15867763036a3edead7450fcfd8a27a3ea5d3a278cbb9960d7225e7d5226bd21d003d83417aa3eee8908f82ae8036437f7aec81f224dd3f085dd0f2623fe
6
+ metadata.gz: af0afea0cbee005eb14a502cc065c8218b5e61ad466c30c32ce9cc912fea3de7471b1c39ae8feef66b29d64af5b63015ae4833e40065157e3fdc67ac141431ad
7
+ data.tar.gz: 60ecf0d725aa18fa9f80e94cfce90ae164d0118b468b128ec2a8ac5f312cdc578d22d2a8e0f7c12ce9d7b5a08c6dd37aca4de917018fc5806ef0d12c75c9d5e8
@@ -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"
@@ -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')
@@ -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.11.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.11.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-08 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
  - - ">="