saal 0.3.3 → 0.3.5
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/bin/saal_envoy_read +9 -1
- data/lib/dbstore.rb +26 -0
- data/lib/denkovi.rb +1 -1
- data/lib/dinrelay.rb +1 -1
- data/lib/envoy.rb +12 -9
- data/lib/http.rb +9 -14
- data/lib/saal.rb +1 -1
- data/lib/sensor.rb +5 -0
- data/saal.gemspec +2 -2
- data/test/dbstore_test.rb +15 -0
- data/test/sensor_test.rb +7 -1
- metadata +11 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '097e00e7d501d49e8b411d07a6a7eff6afe0adf220c3e1757304428c4cc059f1'
|
4
|
+
data.tar.gz: 398f11226d5a182aa92417448afd7b3adf0e6a3d1ab120b8f903eb952e6c131b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ce014accc32521fb1fad84ed552fe92d6ed3798aef83b30769b03244703d80c205d5463c5ebf9b5ad0fff418663d3293add9291d7344b51db4201a634ee0308e
|
7
|
+
data.tar.gz: 3aaeb5d0825733dd3e87d4eb9fb9900f6f7cb5a78c9be3a8168ba7b7afef7ce379d51d8e4a267c59f1fcce86e33075c6a55eb18cfcba65932d138d718f534dd0
|
data/bin/saal_envoy_read
CHANGED
@@ -31,6 +31,14 @@ def fdisp_dec(val)
|
|
31
31
|
end
|
32
32
|
end
|
33
33
|
|
34
|
+
def fdispd(val)
|
35
|
+
if val
|
36
|
+
Time.at(val.to_i).strftime("%Y-%m-%d %k:%M:%S")
|
37
|
+
else
|
38
|
+
"n/a"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
34
42
|
def l(vals, name)
|
35
43
|
sensor = vals[name]
|
36
44
|
if sensor
|
@@ -137,7 +145,7 @@ inverters = envoy.create_sensors
|
|
137
145
|
puts " Found #{envoy.inverters.size} inverters"
|
138
146
|
envoy.inverters.each do |serial|
|
139
147
|
puts " INVERTER: #{serial} \
|
140
|
-
date:#{l(inverters,"inverters_#{serial}_last_report_date")} \
|
148
|
+
date:#{fdispd(l(inverters,"inverters_#{serial}_last_report_date"))} \
|
141
149
|
lastWatts:#{l(inverters,"inverters_#{serial}_w_now")} \
|
142
150
|
maxWatts:#{l(inverters,"inverters_#{serial}_w_max")} \
|
143
151
|
"
|
data/lib/dbstore.rb
CHANGED
@@ -35,6 +35,32 @@ module SAAL
|
|
35
35
|
db_range("AVG", sensor, from, to)
|
36
36
|
end
|
37
37
|
|
38
|
+
def weighted_average(sensor, from, to)
|
39
|
+
total_time = 0
|
40
|
+
total_value = 0.0
|
41
|
+
previous_value = nil
|
42
|
+
start_time = nil
|
43
|
+
initialized = false
|
44
|
+
db_query "SELECT date,value FROM sensor_reads
|
45
|
+
WHERE sensor = '#{db_quote(sensor.to_s)}'
|
46
|
+
AND date >= #{from.to_s}
|
47
|
+
AND date <= #{to.to_s}" do |r|
|
48
|
+
r.each do |row|
|
49
|
+
date = row["date"].to_i
|
50
|
+
value = row["value"].to_f
|
51
|
+
if start_time
|
52
|
+
elapsed = date - start_time
|
53
|
+
total_value += elapsed * previous_value
|
54
|
+
total_time += elapsed
|
55
|
+
initialized = true
|
56
|
+
end
|
57
|
+
start_time = date
|
58
|
+
previous_value = value
|
59
|
+
end
|
60
|
+
end
|
61
|
+
initialized ? total_value / total_time : nil
|
62
|
+
end
|
63
|
+
|
38
64
|
def minimum(sensor, from, to)
|
39
65
|
db_range("MIN", sensor, from, to)
|
40
66
|
end
|
data/lib/denkovi.rb
CHANGED
data/lib/dinrelay.rb
CHANGED
data/lib/envoy.rb
CHANGED
@@ -15,8 +15,9 @@ module SAAL
|
|
15
15
|
|
16
16
|
class PowerEnergy
|
17
17
|
DEFAULT_HOST = "envoy.local"
|
18
|
+
DEFAULT_TOKEN = ""
|
18
19
|
DEFAULT_TIMEOUT = 2
|
19
|
-
DEFAULT_CACHE_TIMEOUT =
|
20
|
+
DEFAULT_CACHE_TIMEOUT = 5
|
20
21
|
DEFAULT_SOURCES = [
|
21
22
|
"production_inverters",
|
22
23
|
"production_phase1", "production_phase2", "production_phase3", "production_total",
|
@@ -30,6 +31,7 @@ module SAAL
|
|
30
31
|
|
31
32
|
def initialize(defs, opts={})
|
32
33
|
@host = defs[:host] || defs['host'] || DEFAULT_HOST
|
34
|
+
@token = defs[:token] || defs['token'] || DEFAULT_TOKEN
|
33
35
|
@timeout = opts[:timeout] || opts['timeout'] || DEFAULT_TIMEOUT
|
34
36
|
@cache_timeout = opts[:cache_timeout] || opts['cache_timeout'] || DEFAULT_CACHE_TIMEOUT
|
35
37
|
@cache = nil
|
@@ -85,7 +87,7 @@ module SAAL
|
|
85
87
|
end
|
86
88
|
|
87
89
|
def read_all
|
88
|
-
response = SAAL::
|
90
|
+
response = SAAL::do_https_get_token(@host, "/production.json?details=1", @token, @timeout)
|
89
91
|
return nil if !response
|
90
92
|
|
91
93
|
values = JSON.parse(response.body)
|
@@ -139,14 +141,16 @@ module SAAL
|
|
139
141
|
|
140
142
|
class ACQuality
|
141
143
|
DEFAULT_HOST = "envoy.local"
|
144
|
+
DEFAULT_TOKEN = ""
|
142
145
|
DEFAULT_TIMEOUT = 2
|
143
|
-
DEFAULT_CACHE_TIMEOUT =
|
146
|
+
DEFAULT_CACHE_TIMEOUT = 5
|
144
147
|
DEFAULT_SOURCES = ["total","phase1","phase2","phase3",]
|
145
148
|
DEFAULT_TYPES = ["frequency","voltage"]
|
146
149
|
DEFAULT_PREFIX = "ac"
|
147
150
|
|
148
151
|
def initialize(defs, opts={})
|
149
152
|
@host = defs[:host] || defs['host'] || DEFAULT_HOST
|
153
|
+
@token = defs[:token] || defs['token'] || DEFAULT_TOKEN
|
150
154
|
@timeout = opts[:timeout] || opts['timeout'] || DEFAULT_TIMEOUT
|
151
155
|
@cache_timeout = opts[:cache_timeout] || opts['cache_timeout'] || DEFAULT_CACHE_TIMEOUT
|
152
156
|
@cache = nil
|
@@ -184,7 +188,7 @@ module SAAL
|
|
184
188
|
end
|
185
189
|
|
186
190
|
def read_all
|
187
|
-
response = SAAL::
|
191
|
+
response = SAAL::do_https_get_token(@host, "/ivp/meters/readings", @token, @timeout)
|
188
192
|
return nil if !response
|
189
193
|
|
190
194
|
values = JSON.parse(response.body)
|
@@ -213,19 +217,18 @@ module SAAL
|
|
213
217
|
end
|
214
218
|
|
215
219
|
class Inverters
|
220
|
+
DEFAULT_HOST = "envoy.local"
|
221
|
+
DEFAULT_TOKEN = nil
|
216
222
|
DEFAULT_TIMEOUT = 2
|
217
223
|
DEFAULT_CACHE_TIMEOUT = 50
|
218
224
|
DEFAULT_SOURCES = []
|
219
225
|
DEFAULT_TYPES = ["w_now"] # "last_report_date", "w_max"
|
220
|
-
DEFAULT_USER = nil
|
221
|
-
DEFAULT_PASSWORD = nil
|
222
226
|
DEFAULT_PREFIX = "inverters"
|
223
227
|
attr_reader :inverters
|
224
228
|
|
225
229
|
def initialize(defs, opts={})
|
226
230
|
@host = defs[:host] || defs['host'] || DEFAULT_HOST
|
227
|
-
@
|
228
|
-
@password = defs[:password] || defs['password'] || DEFAULT_PASSWORD
|
231
|
+
@token = defs[:token] || defs['token'] || DEFAULT_TOKEN
|
229
232
|
@timeout = opts[:timeout] || opts['timeout'] || DEFAULT_TIMEOUT
|
230
233
|
@cache_timeout = opts[:cache_timeout] || opts['cache_timeout'] || DEFAULT_CACHE_TIMEOUT
|
231
234
|
@cache = nil
|
@@ -264,7 +267,7 @@ module SAAL
|
|
264
267
|
|
265
268
|
private
|
266
269
|
def read_all
|
267
|
-
response = SAAL::
|
270
|
+
response = SAAL::do_https_get_token(@host, "/api/v1/production/inverters", @token, @timeout)
|
268
271
|
return nil if !response
|
269
272
|
|
270
273
|
values = JSON.parse(response.body)
|
data/lib/http.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'uri'
|
2
2
|
require 'net/http'
|
3
|
-
require '
|
3
|
+
require 'openssl'
|
4
4
|
|
5
5
|
def SAAL::do_http_get(host, port, path, user, pass, timeout)
|
6
6
|
begin
|
@@ -22,26 +22,21 @@ def SAAL::do_http_get(host, port, path, user, pass, timeout)
|
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
25
|
-
def SAAL::
|
25
|
+
def SAAL::do_https_get_token(host, path, token, timeout)
|
26
26
|
begin
|
27
|
-
|
28
|
-
digest_auth = Net::HTTP::DigestAuth.new
|
29
|
-
uri.user = user
|
30
|
-
uri.password = pass
|
31
|
-
http = Net::HTTP.new(host,port)
|
27
|
+
http = Net::HTTP.new(host,443)
|
32
28
|
# Timeout faster when the other side doesn't respond
|
33
29
|
http.open_timeout = timeout
|
34
30
|
http.read_timeout = timeout
|
31
|
+
http.use_ssl = true
|
32
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
35
33
|
req = Net::HTTP::Get.new(path)
|
34
|
+
req['Accept'] = "application/json"
|
35
|
+
req['Authorization'] = "Bearer #{token}"
|
36
36
|
response = http.request(req)
|
37
|
-
if response.code == "401" && user && pass
|
38
|
-
auth = digest_auth.auth_header uri, response['www-authenticate'], 'GET'
|
39
|
-
req.add_field 'Authorization', auth
|
40
|
-
response = http.request(req)
|
41
|
-
end
|
42
37
|
if response.code != "200"
|
43
|
-
|
44
|
-
|
38
|
+
$stderr.puts "ERROR: Code #{response.code}"
|
39
|
+
$stderr.puts response.body
|
45
40
|
return nil
|
46
41
|
end
|
47
42
|
return response
|
data/lib/saal.rb
CHANGED
data/lib/sensor.rb
CHANGED
@@ -72,6 +72,11 @@ module SAAL
|
|
72
72
|
apply_offset @dbstore.average(@name, from, to)
|
73
73
|
end
|
74
74
|
|
75
|
+
def weighted_average(from, to)
|
76
|
+
return @mock_opts[:weighted_average] if @mock_opts[:weighted_average]
|
77
|
+
apply_offset @dbstore.weighted_average(@name, from, to)
|
78
|
+
end
|
79
|
+
|
75
80
|
def minimum(from, to)
|
76
81
|
return @mock_opts[:minimum] if @mock_opts[:minimum]
|
77
82
|
apply_offset @dbstore.minimum(@name, from, to)
|
data/saal.gemspec
CHANGED
@@ -6,8 +6,8 @@ Gem::Specification.new do |s|
|
|
6
6
|
s.platform = Gem::Platform::RUBY
|
7
7
|
|
8
8
|
s.name = 'saal'
|
9
|
-
s.version = '0.3.
|
10
|
-
s.date = '
|
9
|
+
s.version = '0.3.5'
|
10
|
+
s.date = '2024-02-08'
|
11
11
|
|
12
12
|
s.summary = "Thin abstraction layer for interfacing and recording sensors (currently onewire) and actuators (currently dinrelay)"
|
13
13
|
s.description = <<EOF
|
data/test/dbstore_test.rb
CHANGED
@@ -42,6 +42,21 @@ class TestFileStore < Test::Unit::TestCase
|
|
42
42
|
assert_nil @dbstore.average(:test_sensor, 50, 60)
|
43
43
|
end
|
44
44
|
|
45
|
+
def test_weighted_average
|
46
|
+
db_setup
|
47
|
+
test_values = [[10, 7.323],[12, 5.432],[23, -2.125], [44, 0.123]]
|
48
|
+
test_average = ((12-10)*7.323+(23-12)*5.432+(44-23)*(-2.125)) / (44-10)
|
49
|
+
test_values.each do |values|
|
50
|
+
@dbstore.write(:test_sensor, *values)
|
51
|
+
end
|
52
|
+
|
53
|
+
assert_instance_of Float, @dbstore.average(:test_sensor, 10, 44)
|
54
|
+
assert_in_delta test_average, @dbstore.weighted_average(:test_sensor, 10, 44), 0.001
|
55
|
+
|
56
|
+
# when there are no points it's nil
|
57
|
+
assert_nil @dbstore.weighted_average(:test_sensor, 50, 60)
|
58
|
+
end
|
59
|
+
|
45
60
|
def test_min_max
|
46
61
|
db_setup
|
47
62
|
test_values = [[10, 7.323],[12, 5.432],[23, -2.125], [44, 0.123]]
|
data/test/sensor_test.rb
CHANGED
@@ -31,6 +31,9 @@ class MockDBStore
|
|
31
31
|
def average(sensor, from, to)
|
32
32
|
@value
|
33
33
|
end
|
34
|
+
def weighted_average(sensor, from, to)
|
35
|
+
@value
|
36
|
+
end
|
34
37
|
def minimum(sensor, from, to)
|
35
38
|
@value
|
36
39
|
end
|
@@ -112,6 +115,7 @@ class TestSensor < Test::Unit::TestCase
|
|
112
115
|
assert_equal corrected, sensor.minimum(0,100)
|
113
116
|
assert_equal corrected, sensor.maximum(0,100)
|
114
117
|
assert_equal corrected, sensor.average(0,100)
|
118
|
+
assert_equal corrected, sensor.weighted_average(0,100)
|
115
119
|
end
|
116
120
|
|
117
121
|
def test_linear_correction
|
@@ -125,6 +129,7 @@ class TestSensor < Test::Unit::TestCase
|
|
125
129
|
assert_equal corrected, sensor.minimum(0,100)
|
126
130
|
assert_equal corrected, sensor.maximum(0,100)
|
127
131
|
assert_equal corrected, sensor.average(0,100)
|
132
|
+
assert_equal corrected, sensor.weighted_average(0,100)
|
128
133
|
end
|
129
134
|
|
130
135
|
def test_sensor_type
|
@@ -145,9 +150,10 @@ class TestSensor < Test::Unit::TestCase
|
|
145
150
|
assert_equal 2.0, @mockable.read
|
146
151
|
@mockable.write(3.0)
|
147
152
|
assert_equal 3.0, @mockable.read
|
148
|
-
@mockable.mock_set(:minimum => 1.0, :average => 2.0, :maximum => 3.0, :last_value => 5.0)
|
153
|
+
@mockable.mock_set(:minimum => 1.0, :average => 2.0, :weighted_average => 2.5, :maximum => 3.0, :last_value => 5.0)
|
149
154
|
assert_equal 1.0, @mockable.minimum(0,100)
|
150
155
|
assert_equal 2.0, @mockable.average(0,100)
|
156
|
+
assert_equal 2.5, @mockable.weighted_average(0,100)
|
151
157
|
assert_equal 3.0, @mockable.maximum(0,100)
|
152
158
|
assert_equal 5.0, @mockable.last_value
|
153
159
|
assert_equal 3.0, @mockable.read
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: saal
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Pedro Côrte-Real
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-02-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ownet
|
@@ -71,16 +71,16 @@ description: "A daemon and libraries to create an abstraction layer that interfa
|
|
71
71
|
current and historical values, and allowing changes of state.\n"
|
72
72
|
email: pedro@pedrocr.net
|
73
73
|
executables:
|
74
|
-
- dinrelaystatus
|
75
74
|
- dinrelayset
|
76
|
-
-
|
77
|
-
- saal_dump_database
|
78
|
-
- saal_readall
|
79
|
-
- saal_denkovi_relays
|
75
|
+
- dinrelaystatus
|
80
76
|
- saal_chart
|
81
77
|
- saal_daemon
|
78
|
+
- saal_denkovi_relays
|
79
|
+
- saal_dump_database
|
82
80
|
- saal_envoy_generate_config
|
83
81
|
- saal_envoy_read
|
82
|
+
- saal_import_mysql
|
83
|
+
- saal_readall
|
84
84
|
extensions: []
|
85
85
|
extra_rdoc_files:
|
86
86
|
- README.rdoc
|
@@ -140,7 +140,7 @@ homepage: https://github.com/pedrocr/saal
|
|
140
140
|
licenses:
|
141
141
|
- LGPL-2.1
|
142
142
|
metadata: {}
|
143
|
-
post_install_message:
|
143
|
+
post_install_message:
|
144
144
|
rdoc_options:
|
145
145
|
- "-S"
|
146
146
|
- "-w 2"
|
@@ -159,8 +159,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
159
159
|
- !ruby/object:Gem::Version
|
160
160
|
version: '0'
|
161
161
|
requirements: []
|
162
|
-
rubygems_version: 3.
|
163
|
-
signing_key:
|
162
|
+
rubygems_version: 3.3.5
|
163
|
+
signing_key:
|
164
164
|
specification_version: 2
|
165
165
|
summary: Thin abstraction layer for interfacing and recording sensors (currently onewire)
|
166
166
|
and actuators (currently dinrelay)
|