saal 0.2.24 → 0.3.3
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 +7 -0
- data/bin/saal_chart +49 -4
- data/bin/saal_denkovi_relays +34 -0
- data/bin/saal_envoy_generate_config +53 -0
- data/bin/saal_envoy_read +144 -0
- data/lib/chart.rb +1 -1
- data/lib/chart_data.rb +1 -1
- data/lib/dbstore.rb +15 -18
- data/lib/denkovi.rb +101 -0
- data/lib/dinrelay.rb +2 -18
- data/lib/envoy.rb +287 -0
- data/lib/http.rb +51 -0
- data/lib/outliercache.rb +1 -1
- data/lib/saal.rb +5 -2
- data/lib/sensors.rb +31 -2
- data/saal.gemspec +16 -5
- data/test/chart_data_test.rb +1 -1
- data/test/chart_test.rb +0 -3
- data/test/daemon_test.rb +2 -2
- data/test/dbstore_test.rb +5 -2
- data/test/denkovi.json.erb +39 -0
- data/test/denkovi_test.rb +212 -0
- data/test/dinrelay_test.rb +1 -1
- data/test/sensors_test.rb +5 -5
- data/test/test_db.yml +3 -3
- data/test/test_denkovi_sensors.yml +39 -0
- data/test/test_helper.rb +2 -2
- data/test/test_sensors.yml +1 -1
- metadata +72 -42
- data/bin/saal_chart~ +0 -90
- data/bin/saal_daemon~ +0 -31
data/lib/dinrelay.rb
CHANGED
@@ -42,6 +42,7 @@ module SAAL
|
|
42
42
|
@cache_timeout = opts[:cache_timeout] || opts['cache_timeout'] || DEFAULT_CACHE_TIMEOUT
|
43
43
|
@cache = nil
|
44
44
|
@cachehit = nil
|
45
|
+
@cachetime = nil
|
45
46
|
end
|
46
47
|
|
47
48
|
def state(num)
|
@@ -60,25 +61,8 @@ module SAAL
|
|
60
61
|
|
61
62
|
private
|
62
63
|
def do_get(path)
|
63
|
-
|
64
|
-
http = Net::HTTP.new(@host,@port)
|
65
|
-
# Timeout faster when the other side doesn't respond
|
66
|
-
http.open_timeout = @timeout
|
67
|
-
http.read_timeout = @timeout
|
68
|
-
req = Net::HTTP::Get.new(path)
|
69
|
-
req.basic_auth @user, @pass
|
70
|
-
response = http.request(req)
|
71
|
-
if response.code != "200"
|
72
|
-
#$stderr.puts "ERROR: Code #{response.code}"
|
73
|
-
#$stderr.puts response.body
|
74
|
-
return nil
|
75
|
-
end
|
76
|
-
return response
|
77
|
-
rescue Exception
|
78
|
-
return nil
|
79
|
-
end
|
64
|
+
SAAL::do_http_get(@host, @port, path, @user, @pass, @timeout)
|
80
65
|
end
|
81
|
-
|
82
66
|
def parse_index_html(str)
|
83
67
|
doc = Nokogiri::HTML(str)
|
84
68
|
outlets = doc.css('tr[bgcolor="#F4F4F4"]')
|
data/lib/envoy.rb
ADDED
@@ -0,0 +1,287 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module SAAL
|
4
|
+
module Envoy
|
5
|
+
class PowerEnergyUnderlying < SensorUnderlying
|
6
|
+
def initialize(key, production)
|
7
|
+
@key = key
|
8
|
+
@production = production
|
9
|
+
end
|
10
|
+
|
11
|
+
def read(uncached = false)
|
12
|
+
@production.read_val(@key)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class PowerEnergy
|
17
|
+
DEFAULT_HOST = "envoy.local"
|
18
|
+
DEFAULT_TIMEOUT = 2
|
19
|
+
DEFAULT_CACHE_TIMEOUT = 50
|
20
|
+
DEFAULT_SOURCES = [
|
21
|
+
"production_inverters",
|
22
|
+
"production_phase1", "production_phase2", "production_phase3", "production_total",
|
23
|
+
"net_consumption_phase1", "net_consumption_phase2", "net_consumption_phase3", "net_consumption_total",
|
24
|
+
"total_consumption_phase1", "total_consumption_phase2", "total_consumption_phase3", "total_consumption_total",
|
25
|
+
]
|
26
|
+
DEFAULT_TYPES = [
|
27
|
+
"w_now", "wh_lifetime", "va_now", "vah_lifetime",
|
28
|
+
]
|
29
|
+
DEFAULT_PREFIX = "pv"
|
30
|
+
|
31
|
+
def initialize(defs, opts={})
|
32
|
+
@host = defs[:host] || defs['host'] || DEFAULT_HOST
|
33
|
+
@timeout = opts[:timeout] || opts['timeout'] || DEFAULT_TIMEOUT
|
34
|
+
@cache_timeout = opts[:cache_timeout] || opts['cache_timeout'] || DEFAULT_CACHE_TIMEOUT
|
35
|
+
@cache = nil
|
36
|
+
@cachetime = nil
|
37
|
+
@sources = defs[:sources] || defs['source'] || DEFAULT_SOURCES
|
38
|
+
@types = defs[:types] || defs['types'] || DEFAULT_TYPES
|
39
|
+
@prefix = defs[:prefix] || defs['prefix'] || DEFAULT_PREFIX
|
40
|
+
end
|
41
|
+
|
42
|
+
def read_val(name)
|
43
|
+
if !@cachetime or @cachetime < Time.now - @cache_timeout
|
44
|
+
@cache = read_all()
|
45
|
+
@cachetime = Time.now
|
46
|
+
end
|
47
|
+
return @cache ? @cache[name] : nil
|
48
|
+
end
|
49
|
+
|
50
|
+
def create_sensors
|
51
|
+
sensors = {}
|
52
|
+
@sources.product(@types).each do |source, type|
|
53
|
+
key = "#{@prefix}_#{source}_#{type}"
|
54
|
+
sensors[key] = PowerEnergyUnderlying.new(key, self)
|
55
|
+
end
|
56
|
+
sensors
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
def save_vals(dest, name, source)
|
61
|
+
{
|
62
|
+
"wNow" => "w_now",
|
63
|
+
"apprntPwr" => "va_now",
|
64
|
+
"whLifetime" => "wh_lifetime",
|
65
|
+
"vahLifetime" => "vah_lifetime",
|
66
|
+
}.each do |type, label|
|
67
|
+
dest["#{@prefix}_#{name}_#{label}"] = source[type]
|
68
|
+
end
|
69
|
+
|
70
|
+
# Hack around the fact that apprntPwr is broken on the total consumption
|
71
|
+
# calculation for the three-phase sum at least
|
72
|
+
# In those cases it seems to be missing a divide by three, so when the
|
73
|
+
# calculation for voltage and current alone is close do the extra divide
|
74
|
+
va_now = dest["#{@prefix}_#{name}_va_now"]
|
75
|
+
if va_now && !name.include?("phase")
|
76
|
+
voltage = source["rmsVoltage"]
|
77
|
+
current = source["rmsCurrent"]
|
78
|
+
if voltage && current
|
79
|
+
va_alt = voltage * current
|
80
|
+
if ((va_alt / va_now) - 1.0).abs < 0.05
|
81
|
+
dest["#{@prefix}_#{name}_va_now"] = va_now / 3.0
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def read_all
|
88
|
+
response = SAAL::do_http_get(@host, 80, "/production.json?details=1", nil, nil, @timeout)
|
89
|
+
return nil if !response
|
90
|
+
|
91
|
+
values = JSON.parse(response.body)
|
92
|
+
outputs = {}
|
93
|
+
|
94
|
+
values["production"].each do |source|
|
95
|
+
type = source["type"]
|
96
|
+
case type
|
97
|
+
when "inverters"
|
98
|
+
save_vals(outputs, "production_inverters", source)
|
99
|
+
when "eim"
|
100
|
+
if source["lines"]
|
101
|
+
save_vals(outputs, "production_phase1", source["lines"][0])
|
102
|
+
save_vals(outputs, "production_phase2", source["lines"][1])
|
103
|
+
save_vals(outputs, "production_phase3", source["lines"][2])
|
104
|
+
end
|
105
|
+
save_vals(outputs, "production_total", source)
|
106
|
+
else
|
107
|
+
$stderr.puts "WARNING: ENVOY: don't know source type #{type}"
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
values["consumption"].each do |source|
|
112
|
+
type = {
|
113
|
+
"total-consumption" => "total",
|
114
|
+
"net-consumption" => "net",
|
115
|
+
}[source["measurementType"]] || "unknown";
|
116
|
+
|
117
|
+
if source["lines"]
|
118
|
+
save_vals(outputs, "#{type}_consumption_phase1", source["lines"][0])
|
119
|
+
save_vals(outputs, "#{type}_consumption_phase2", source["lines"][1])
|
120
|
+
save_vals(outputs, "#{type}_consumption_phase3", source["lines"][2])
|
121
|
+
end
|
122
|
+
save_vals(outputs, "#{type}_consumption_total", source)
|
123
|
+
end
|
124
|
+
|
125
|
+
outputs
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
class ACQualityUnderlying < SensorUnderlying
|
130
|
+
def initialize(key, production)
|
131
|
+
@key = key
|
132
|
+
@production = production
|
133
|
+
end
|
134
|
+
|
135
|
+
def read(uncached = false)
|
136
|
+
@production.read_val(@key)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
class ACQuality
|
141
|
+
DEFAULT_HOST = "envoy.local"
|
142
|
+
DEFAULT_TIMEOUT = 2
|
143
|
+
DEFAULT_CACHE_TIMEOUT = 50
|
144
|
+
DEFAULT_SOURCES = ["total","phase1","phase2","phase3",]
|
145
|
+
DEFAULT_TYPES = ["frequency","voltage"]
|
146
|
+
DEFAULT_PREFIX = "ac"
|
147
|
+
|
148
|
+
def initialize(defs, opts={})
|
149
|
+
@host = defs[:host] || defs['host'] || DEFAULT_HOST
|
150
|
+
@timeout = opts[:timeout] || opts['timeout'] || DEFAULT_TIMEOUT
|
151
|
+
@cache_timeout = opts[:cache_timeout] || opts['cache_timeout'] || DEFAULT_CACHE_TIMEOUT
|
152
|
+
@cache = nil
|
153
|
+
@cachetime = nil
|
154
|
+
@sources = defs[:sources] || defs['source'] || DEFAULT_SOURCES
|
155
|
+
@types = defs[:types] || defs['types'] || DEFAULT_TYPES
|
156
|
+
@prefix = defs[:prefix] || defs['prefix'] || DEFAULT_PREFIX
|
157
|
+
end
|
158
|
+
|
159
|
+
def read_val(name)
|
160
|
+
if !@cachetime or @cachetime < Time.now - @cache_timeout
|
161
|
+
@cache = read_all()
|
162
|
+
@cachetime = Time.now
|
163
|
+
end
|
164
|
+
return @cache ? @cache[name] : nil
|
165
|
+
end
|
166
|
+
|
167
|
+
def create_sensors
|
168
|
+
sensors = {}
|
169
|
+
@sources.product(@types).each do |source, type|
|
170
|
+
key = "#{@prefix}_#{source}_#{type}"
|
171
|
+
sensors[key] = ACQualityUnderlying.new(key, self)
|
172
|
+
end
|
173
|
+
sensors
|
174
|
+
end
|
175
|
+
|
176
|
+
private
|
177
|
+
def save_vals(dest, name, source)
|
178
|
+
{
|
179
|
+
"voltage" => "voltage",
|
180
|
+
"freq" => "frequency",
|
181
|
+
}.each do |type, label|
|
182
|
+
dest["#{@prefix}_#{name}_#{label}"] = source[type]
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
def read_all
|
187
|
+
response = SAAL::do_http_get(@host, 80, "/ivp/meters/readings", nil, nil, @timeout)
|
188
|
+
return nil if !response
|
189
|
+
|
190
|
+
values = JSON.parse(response.body)
|
191
|
+
outputs = {}
|
192
|
+
source = values[0]
|
193
|
+
save_vals(outputs, "total", source)
|
194
|
+
if source["channels"]
|
195
|
+
save_vals(outputs, "phase1", source["channels"][0])
|
196
|
+
save_vals(outputs, "phase2", source["channels"][1])
|
197
|
+
save_vals(outputs, "phase3", source["channels"][2])
|
198
|
+
end
|
199
|
+
|
200
|
+
outputs
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
class InverterUnderlying < SensorUnderlying
|
205
|
+
def initialize(key, inverters)
|
206
|
+
@key = key
|
207
|
+
@inverters = inverters
|
208
|
+
end
|
209
|
+
|
210
|
+
def read(uncached = false)
|
211
|
+
@inverters.read_val(@key)
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
class Inverters
|
216
|
+
DEFAULT_TIMEOUT = 2
|
217
|
+
DEFAULT_CACHE_TIMEOUT = 50
|
218
|
+
DEFAULT_SOURCES = []
|
219
|
+
DEFAULT_TYPES = ["w_now"] # "last_report_date", "w_max"
|
220
|
+
DEFAULT_USER = nil
|
221
|
+
DEFAULT_PASSWORD = nil
|
222
|
+
DEFAULT_PREFIX = "inverters"
|
223
|
+
attr_reader :inverters
|
224
|
+
|
225
|
+
def initialize(defs, opts={})
|
226
|
+
@host = defs[:host] || defs['host'] || DEFAULT_HOST
|
227
|
+
@user = defs[:user] || defs['user'] || DEFAULT_USER
|
228
|
+
@password = defs[:password] || defs['password'] || DEFAULT_PASSWORD
|
229
|
+
@timeout = opts[:timeout] || opts['timeout'] || DEFAULT_TIMEOUT
|
230
|
+
@cache_timeout = opts[:cache_timeout] || opts['cache_timeout'] || DEFAULT_CACHE_TIMEOUT
|
231
|
+
@cache = nil
|
232
|
+
@cachetime = nil
|
233
|
+
@inverters_list = {}
|
234
|
+
@inverters = defs[:inverters] || defs['inverters'] || DEFAULT_SOURCES
|
235
|
+
@types = defs[:types] || defs['types'] || DEFAULT_TYPES
|
236
|
+
@prefix = defs[:prefix] || defs['prefix'] || DEFAULT_PREFIX
|
237
|
+
end
|
238
|
+
|
239
|
+
def read_val(name)
|
240
|
+
if !@cachetime or @cachetime < Time.now - @cache_timeout
|
241
|
+
@cache = read_all()
|
242
|
+
@cachetime = Time.now
|
243
|
+
end
|
244
|
+
return @cache ? @cache[name] : nil
|
245
|
+
end
|
246
|
+
|
247
|
+
def enumerate
|
248
|
+
read_val("foo") # Force a read to make sure the inverter serials are stored
|
249
|
+
@inverters_list.keys
|
250
|
+
end
|
251
|
+
|
252
|
+
def set_all_inverters!
|
253
|
+
@inverters = self.enumerate
|
254
|
+
end
|
255
|
+
|
256
|
+
def create_sensors
|
257
|
+
sensors = {}
|
258
|
+
@inverters.product(@types).each do |source, type|
|
259
|
+
key = "#{@prefix}_#{source}_#{type}"
|
260
|
+
sensors[key] = InverterUnderlying.new(key, self)
|
261
|
+
end
|
262
|
+
sensors
|
263
|
+
end
|
264
|
+
|
265
|
+
private
|
266
|
+
def read_all
|
267
|
+
response = SAAL::do_http_get_digest(@host, 80, "/api/v1/production/inverters", @user, @password, @timeout)
|
268
|
+
return nil if !response
|
269
|
+
|
270
|
+
values = JSON.parse(response.body)
|
271
|
+
inverters = {}
|
272
|
+
values.each do |inverter|
|
273
|
+
serial = inverter["serialNumber"]
|
274
|
+
@inverters_list[serial] = true
|
275
|
+
{"lastReportDate" => "last_report_date",
|
276
|
+
"lastReportWatts" => "w_now",
|
277
|
+
"maxReportWatts" => "w_max",
|
278
|
+
}.each do |type, label|
|
279
|
+
inverters["#{@prefix}_#{serial}_#{label}"] = inverter[type]
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
283
|
+
inverters
|
284
|
+
end
|
285
|
+
end
|
286
|
+
end
|
287
|
+
end
|
data/lib/http.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'uri'
|
2
|
+
require 'net/http'
|
3
|
+
require 'net/http/digest_auth'
|
4
|
+
|
5
|
+
def SAAL::do_http_get(host, port, path, user, pass, timeout)
|
6
|
+
begin
|
7
|
+
http = Net::HTTP.new(host,port)
|
8
|
+
# Timeout faster when the other side doesn't respond
|
9
|
+
http.open_timeout = timeout
|
10
|
+
http.read_timeout = timeout
|
11
|
+
req = Net::HTTP::Get.new(path)
|
12
|
+
req.basic_auth(user, pass) if user && pass
|
13
|
+
response = http.request(req)
|
14
|
+
if response.code != "200"
|
15
|
+
#$stderr.puts "ERROR: Code #{response.code}"
|
16
|
+
#$stderr.puts response.body
|
17
|
+
return nil
|
18
|
+
end
|
19
|
+
return response
|
20
|
+
rescue Exception
|
21
|
+
return nil
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def SAAL::do_http_get_digest(host, port, path, user, pass, timeout)
|
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)
|
32
|
+
# Timeout faster when the other side doesn't respond
|
33
|
+
http.open_timeout = timeout
|
34
|
+
http.read_timeout = timeout
|
35
|
+
req = Net::HTTP::Get.new(path)
|
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
|
+
if response.code != "200"
|
43
|
+
#$stderr.puts "ERROR: Code #{response.code}"
|
44
|
+
#$stderr.puts response.body
|
45
|
+
return nil
|
46
|
+
end
|
47
|
+
return response
|
48
|
+
rescue Exception
|
49
|
+
return nil
|
50
|
+
end
|
51
|
+
end
|
data/lib/outliercache.rb
CHANGED
@@ -41,7 +41,7 @@ module SAAL
|
|
41
41
|
def valid_cache
|
42
42
|
@compcache.sort!
|
43
43
|
central = @compcache[1..(@compcache.size-2)]
|
44
|
-
sum = central.inject(0.0){|
|
44
|
+
sum = central.inject(0.0){|csum,el| csum+el}
|
45
45
|
return false if sum == 0.0
|
46
46
|
average = sum/central.size
|
47
47
|
central.each do |el|
|
data/lib/saal.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
require 'yaml'
|
2
|
-
require "
|
2
|
+
require "mysql2"
|
3
3
|
require 'ownet'
|
4
4
|
require 'nokogiri'
|
5
5
|
require 'erb'
|
@@ -10,7 +10,7 @@ module SAAL
|
|
10
10
|
DBCONF = CONFDIR+"database.yml"
|
11
11
|
CHARTSCONF = CONFDIR+"charts.yml"
|
12
12
|
|
13
|
-
VERSION = '0.
|
13
|
+
VERSION = '0.3.3'
|
14
14
|
end
|
15
15
|
|
16
16
|
require File.dirname(__FILE__)+'/dbstore.rb'
|
@@ -23,4 +23,7 @@ require File.dirname(__FILE__)+'/chart.rb'
|
|
23
23
|
require File.dirname(__FILE__)+'/chart_data.rb'
|
24
24
|
require File.dirname(__FILE__)+'/outliercache.rb'
|
25
25
|
require File.dirname(__FILE__)+'/dinrelay.rb'
|
26
|
+
require File.dirname(__FILE__)+'/envoy.rb'
|
27
|
+
require File.dirname(__FILE__)+'/http.rb'
|
28
|
+
require File.dirname(__FILE__)+'/denkovi.rb'
|
26
29
|
|
data/lib/sensors.rb
CHANGED
@@ -40,9 +40,38 @@ module SAAL
|
|
40
40
|
defs.merge!('name' => outlet_descriptions[num])
|
41
41
|
Sensor.new(dbstore, oname, DINRelay::Outlet.new(num.to_i, og), defs, opts)
|
42
42
|
end
|
43
|
+
elsif defs['envoy_power_energy']
|
44
|
+
defs = defs['envoy_power_energy'].merge('prefix' => name)
|
45
|
+
pe = SAAL::Envoy::PowerEnergy::new(defs)
|
46
|
+
sensors = pe.create_sensors
|
47
|
+
return sensors.map do |name, underlying|
|
48
|
+
Sensor.new(dbstore, name, underlying, defs, opts)
|
49
|
+
end
|
50
|
+
elsif defs['envoy_ac_quality']
|
51
|
+
defs = defs['envoy_ac_quality'].merge('prefix' => name)
|
52
|
+
pe = SAAL::Envoy::ACQuality::new(defs)
|
53
|
+
sensors = pe.create_sensors
|
54
|
+
return sensors.map do |name, underlying|
|
55
|
+
Sensor.new(dbstore, name, underlying, defs, opts)
|
56
|
+
end
|
57
|
+
elsif defs['envoy_inverters']
|
58
|
+
defs = defs['envoy_inverters'].merge('prefix' => name)
|
59
|
+
pe = SAAL::Envoy::Inverters::new(defs)
|
60
|
+
sensors = pe.create_sensors
|
61
|
+
return sensors.map do |name, underlying|
|
62
|
+
Sensor.new(dbstore, name, underlying, defs, opts)
|
63
|
+
end
|
64
|
+
elsif defs['denkovi']
|
65
|
+
defs = defs['denkovi'].merge('prefix' => name)
|
66
|
+
denkovi = SAAL::Denkovi::OutletGroup::new(defs)
|
67
|
+
sensors = denkovi.create_sensors
|
68
|
+
return sensors.map do |name, vals|
|
69
|
+
underlying, description = vals
|
70
|
+
defs.merge!('name' => description)
|
71
|
+
Sensor.new(dbstore, name, underlying, defs, opts)
|
72
|
+
end
|
43
73
|
else
|
44
|
-
|
45
|
-
"from the configuration for #{name}"
|
74
|
+
$stderror.puts "WARNING: Couldn't figure out a valid sensor type for #{name}"
|
46
75
|
end
|
47
76
|
end
|
48
77
|
end
|
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.
|
10
|
-
s.date = '
|
9
|
+
s.version = '0.3.3'
|
10
|
+
s.date = '2020-12-28'
|
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
|
@@ -19,6 +19,7 @@ EOF
|
|
19
19
|
s.authors = ["Pedro Côrte-Real"]
|
20
20
|
s.email = 'pedro@pedrocr.net'
|
21
21
|
s.homepage = 'https://github.com/pedrocr/saal'
|
22
|
+
s.licenses = 'LGPL-2.1'
|
22
23
|
|
23
24
|
s.require_paths = %w[lib]
|
24
25
|
|
@@ -28,9 +29,10 @@ EOF
|
|
28
29
|
|
29
30
|
s.executables = Dir.glob("bin/*").map{|f| f.gsub('bin/','')}
|
30
31
|
|
31
|
-
s.
|
32
|
-
s.
|
33
|
-
s.
|
32
|
+
s.add_runtime_dependency 'ownet', "~>0.2"
|
33
|
+
s.add_runtime_dependency 'mysql2', "~>0.5"
|
34
|
+
s.add_runtime_dependency 'nokogiri', '~>1.8'
|
35
|
+
s.add_runtime_dependency 'net-http-digest_auth', '~>1.4'
|
34
36
|
|
35
37
|
# = MANIFEST =
|
36
38
|
s.files = %w[
|
@@ -43,7 +45,10 @@ EOF
|
|
43
45
|
bin/dinrelaystatus
|
44
46
|
bin/saal_chart
|
45
47
|
bin/saal_daemon
|
48
|
+
bin/saal_denkovi_relays
|
46
49
|
bin/saal_dump_database
|
50
|
+
bin/saal_envoy_generate_config
|
51
|
+
bin/saal_envoy_read
|
47
52
|
bin/saal_import_mysql
|
48
53
|
bin/saal_readall
|
49
54
|
lib/chart.rb
|
@@ -51,7 +56,10 @@ EOF
|
|
51
56
|
lib/charts.rb
|
52
57
|
lib/daemon.rb
|
53
58
|
lib/dbstore.rb
|
59
|
+
lib/denkovi.rb
|
54
60
|
lib/dinrelay.rb
|
61
|
+
lib/envoy.rb
|
62
|
+
lib/http.rb
|
55
63
|
lib/outliercache.rb
|
56
64
|
lib/owsensor.rb
|
57
65
|
lib/saal.rb
|
@@ -63,6 +71,8 @@ EOF
|
|
63
71
|
test/charts_test.rb
|
64
72
|
test/daemon_test.rb
|
65
73
|
test/dbstore_test.rb
|
74
|
+
test/denkovi.json.erb
|
75
|
+
test/denkovi_test.rb
|
66
76
|
test/dinrelay.html.erb
|
67
77
|
test/dinrelay_test.rb
|
68
78
|
test/nonexistant_sensor.yml
|
@@ -71,6 +81,7 @@ EOF
|
|
71
81
|
test/sensors_test.rb
|
72
82
|
test/test_charts.yml
|
73
83
|
test/test_db.yml
|
84
|
+
test/test_denkovi_sensors.yml
|
74
85
|
test/test_dinrelay_sensors.yml
|
75
86
|
test/test_helper.rb
|
76
87
|
test/test_sensor_cleanups.yml
|