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 +4 -4
- data/.github/workflows/push.yml +1 -1
- data/.rubocop.yml +1 -1
- data/Gemfile +0 -3
- data/README.md +8 -6
- data/lib/senec/connection.rb +30 -0
- data/lib/senec/request.rb +31 -19
- data/lib/senec/state.rb +21 -17
- data/lib/senec/version.rb +1 -1
- data/lib/senec.rb +1 -0
- data/senec.gemspec +4 -2
- metadata +33 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0d619a385d96958f3d69b8486977b64ec6c0d758dff3179138714ba22f7915d5
|
4
|
+
data.tar.gz: 52991e9de034ebeda649ebf48f138d9f3dc71d69d005e25d8e45bcac2bd79804
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: af0afea0cbee005eb14a502cc065c8218b5e61ad466c30c32ce9cc912fea3de7471b1c39ae8feef66b29d64af5b63015ae4833e40065157e3fdc67ac141431ad
|
7
|
+
data.tar.gz: 60ecf0d725aa18fa9f80e94cfce90ae164d0118b468b128ec2a8ac5f312cdc578d22d2a8e0f7c12ce9d7b5a08c6dd37aca4de917018fc5806ef0d12c75c9d5e8
|
data/.github/workflows/push.yml
CHANGED
data/.rubocop.yml
CHANGED
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
|
-
|
27
|
-
request = Senec::Request.new
|
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
|
-
|
68
|
-
|
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
|
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(
|
8
|
-
@
|
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 :
|
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
|
-
|
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
|
95
|
-
@
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
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
|
-
|
107
|
+
response
|
107
108
|
end
|
108
109
|
end
|
109
110
|
|
110
111
|
def url
|
111
|
-
|
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(
|
6
|
-
@
|
7
|
-
@schema = schema
|
3
|
+
def initialize(connection:)
|
4
|
+
@connection = connection
|
8
5
|
end
|
9
6
|
|
10
|
-
attr_reader :
|
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
|
-
|
35
|
-
|
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
|
-
|
39
|
-
end
|
34
|
+
res.body
|
40
35
|
end
|
41
36
|
|
42
|
-
# Use the JavaScript file
|
43
|
-
def url
|
44
|
-
|
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
data/lib/senec.rb
CHANGED
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.
|
14
|
-
spec.add_runtime_dependency '
|
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.
|
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
|
11
|
+
date: 2023-09-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
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.
|
98
|
+
version: 3.2.0
|
70
99
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
71
100
|
requirements:
|
72
101
|
- - ">="
|