saal 0.3.3 → 0.3.5

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: 90aa53b1093427163af28bee630532e79ccefea47de44463641c3e387f038640
4
- data.tar.gz: 41fca314cb32d91ca10bfb1982cf7e60a6b584c3c521b8ddcd148b18f465fd86
3
+ metadata.gz: '097e00e7d501d49e8b411d07a6a7eff6afe0adf220c3e1757304428c4cc059f1'
4
+ data.tar.gz: 398f11226d5a182aa92417448afd7b3adf0e6a3d1ab120b8f903eb952e6c131b
5
5
  SHA512:
6
- metadata.gz: ff26de3ff3cca4750a365b9672a82165d449f7c11fb3bd57d7f3f27758636a521d766ae99dc84b50cd30e940453eb30826ad485e44f9e50d723bb5625cd07915
7
- data.tar.gz: f93e18eacc3a2eb6555c95b9ea91f74506a39af91c6083ab6dbb3acc1ef2d83387db9ed59a573afcb7bbd1354cfdf7af51ec11122d9f48f287baf273c235debf
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
@@ -30,7 +30,7 @@ module SAAL
30
30
 
31
31
  class OutletGroup
32
32
  DEFAULT_TIMEOUT = 2
33
- DEFAULT_CACHE_TIMEOUT = 60
33
+ DEFAULT_CACHE_TIMEOUT = 5
34
34
  DEFAULT_OUTLETS = {}
35
35
  DEFAULT_DESCRIPTIONS = {}
36
36
 
data/lib/dinrelay.rb CHANGED
@@ -29,7 +29,7 @@ module SAAL
29
29
 
30
30
  class OutletGroup
31
31
  DEFAULT_TIMEOUT = 2
32
- DEFAULT_CACHE_TIMEOUT = 60
32
+ DEFAULT_CACHE_TIMEOUT = 5
33
33
 
34
34
  attr_accessor :host, :port, :user, :pass, :timeout, :cache_timeout
35
35
 
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 = 50
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::do_http_get(@host, 80, "/production.json?details=1", nil, nil, @timeout)
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 = 50
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::do_http_get(@host, 80, "/ivp/meters/readings", nil, nil, @timeout)
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
- @user = defs[:user] || defs['user'] || DEFAULT_USER
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::do_http_get_digest(@host, 80, "/api/v1/production/inverters", @user, @password, @timeout)
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 'net/http/digest_auth'
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::do_http_get_digest(host, port, path, user, pass, timeout)
25
+ def SAAL::do_https_get_token(host, path, token, timeout)
26
26
  begin
27
- uri = URI.parse "http://#{host}:#{port}/#{path}"
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
- #$stderr.puts "ERROR: Code #{response.code}"
44
- #$stderr.puts response.body
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
@@ -10,7 +10,7 @@ module SAAL
10
10
  DBCONF = CONFDIR+"database.yml"
11
11
  CHARTSCONF = CONFDIR+"charts.yml"
12
12
 
13
- VERSION = '0.3.3'
13
+ VERSION = '0.3.5'
14
14
  end
15
15
 
16
16
  require File.dirname(__FILE__)+'/dbstore.rb'
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.3'
10
- s.date = '2020-12-28'
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.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: 2020-12-28 00:00:00.000000000 Z
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
- - saal_import_mysql
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.1.2
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)