saal 0.2.13 → 0.2.14

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -1,13 +1,13 @@
1
1
  = saal
2
2
 
3
- saal stands for Sensor and Actuator Abstraction Layer, and it aims to handle the mechanics of accessing sensors and actuators and logging their state over time. In its present state it is capable of reading from any set of one wire sensors attached one or more owserver processes from the owfs project. In the future other forms of sensors as well as actuators can be added.
3
+ saal stands for Sensor and Actuator Abstraction Layer, and it aims to handle the mechanics of accessing sensors and actuators and logging their state over time. In its present state it is capable of reading from any set of one wire sensors attached one or more owserver processes from the owfs project. It is also able to read and actuate the DIN mounted IP relay from digital loggers (http://www.digital-loggers.com/din.html). In the future other forms of sensors as well as actuators can be added.
4
4
 
5
- Based on a single definition of available sensors several features are available:
5
+ Based on a single definition of available sensors/actuators several features are available:
6
6
 
7
- * An API to read from the sensors
7
+ * An API to read/write to sensors/actuators
8
8
  * A daemon that periodically records all sensor values into a MySQL database
9
9
  * An API to interrogate the database of recorded values
10
- * A graphing API and example code to produce ongoing displays of the sensor reads
10
+ * A graphing API and full program to produce charts from the stored sensor reads
11
11
 
12
12
  An example of the usage of saal can be seen at http://www.corujas.net.
13
13
 
@@ -60,16 +60,37 @@ Both arguments to average are unix timestamps in UTC timezone.
60
60
 
61
61
  == Charting
62
62
 
63
- SAAL::ChartData provides some helper methods to produce a time series of values for a sensor where each point is the average of the sensor reads for the interval:
63
+ After you've gotten sensor logging working and some values in the database you can start creating charts based on it. Here's an example /etc/saal/charts.yml file:
64
64
 
65
- saal = SAAL::Sensors.new
66
- chart = SAAL::ChartData.new(saal.fake_temp)
67
- now = Time.now.utc.to_i
68
- # Average fake_temp over the last 10 minutes divided in 4 intervals
69
- chart.get_data(now - 60*10, now, 4)
70
- #=> [19.1555206999183, 28.3404493331909, 56.4694658915202, 50.4347496032715]
65
+ day:
66
+ sensors: [temp_exterior, hum_exterior, pressure]
67
+ last: 24
68
+ periods: hours
71
69
 
72
- See saal_chart for an example of creating chart images over several time spans including serveral sensors using Google's chart API.
70
+ week:
71
+ sensors: [temp_exterior, hum_exterior, pressure]
72
+ last: 7
73
+ periods: days
74
+
75
+ 4week:
76
+ sensors: [temp_exterior, hum_exterior, pressure]
77
+ last: 4
78
+ periods: weeks
79
+ alignlabels: left
80
+
81
+ year:
82
+ sensors: [temp_exterior, hum_exterior, pressure]
83
+ last: 12
84
+ periods: months
85
+
86
+ 4year:
87
+ sensors: [temp_exterior, hum_exterior, pressure]
88
+ last: 4
89
+ periods: years
90
+
91
+ With this in place you can now run "saal_chart <some_directory>" and get 5 png files produced with the Google charts API that show the data recorded in the database over the given periods. This is almost exactly the config that generates the graphs at http://www.corujas.net.
92
+
93
+ The charting code handles range selection and period naming automatically, so all possibilities of number and type of periods are possible.
73
94
 
74
95
  == Author
75
96
 
data/TODO CHANGED
@@ -1,5 +1,6 @@
1
1
  TODO
2
- - Make the sensor storage in saal_daemon threaded so a single sensor read can't stall everything else for a long time
2
+ - Only enable the outlier proofing for the daemon so things like saal_readall don't block for a long time on unavailable sensors trying to seed the outlier cache
3
+ - Make the sensor value storage in saal_daemon threaded so a single sensor read can't stall everything else for a long time
3
4
  !-Index the value column of the sensor reads for minimum and maximum
4
5
  - Change the filtering operations (e.g., outliercache) so that the raw value is always stored in the database
5
6
  - Make the outliercache filter based on the expected sensor range (e.g. -20-50 in temperature and 800-1200 in pressure) so as to not be overly sensitive when around 0)
data/bin/saal_readall CHANGED
File without changes
data/lib/dinrelay.rb CHANGED
@@ -29,23 +29,31 @@ module SAAL
29
29
 
30
30
  class OutletGroup
31
31
  DEFAULT_TIMEOUT = 2
32
+ DEFAULT_CACHE_TIMEOUT = 60
32
33
 
33
- attr_reader :timeout
34
+ attr_accessor :host, :port, :user, :pass, :timeout, :cache_timeout
34
35
 
35
36
  def initialize(opts={})
36
37
  @host = opts[:host] || opts['host'] || 'localhost'
37
38
  @port = opts[:port] || opts['port'] || 80
38
39
  @user = opts[:user] || opts['user'] || 'admin'
39
40
  @pass = opts[:pass] || opts['pass'] || '1234'
40
- @timeout = opts[:timeout] || DEFAULT_TIMEOUT
41
+ @timeout = opts[:timeout] || opts['timeout'] || DEFAULT_TIMEOUT
42
+ @cache_timeout = opts[:cache_timeout] || opts['cache_timeout'] || DEFAULT_CACHE_TIMEOUT
43
+ @cache = nil
44
+ @cachehit = nil
41
45
  end
42
46
 
43
47
  def state(num)
44
- response = do_get('/index.htm')
45
- return response ? parse_index_html(response.body)[num] : nil
48
+ if !@cachetime or @cachetime < Time.now - @cache_timeout
49
+ @cache = do_get('/index.htm')
50
+ @cachetime = Time.now
51
+ end
52
+ return @cache ? parse_index_html(@cache.body)[num] : nil
46
53
  end
47
54
 
48
55
  def set_state(num, state)
56
+ @cachetime = nil
49
57
  response = do_get("/outlet?#{num}=#{state}")
50
58
  response != nil
51
59
  end
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.2.13'
13
+ VERSION = '0.2.14'
14
14
  end
15
15
 
16
16
  require File.dirname(__FILE__)+'/dbstore.rb'
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.2.13'
10
- s.date = '2011-06-03'
9
+ s.version = '0.2.14'
10
+ s.date = '2011-06-21'
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
@@ -21,6 +21,7 @@ class TestDINRelay < Test::Unit::TestCase
21
21
  def do_GET(req, res)
22
22
  sleep @sleep
23
23
  @feedback[:uri] = req.request_uri.to_s
24
+ @feedback[:nrequests] = (@feedback[:nrequests]||0)+1
24
25
  WEBrick::HTTPAuth.basic_auth(req, res, "My Realm") {|user, pass|
25
26
  user == @user && pass == @pass
26
27
  }
@@ -105,6 +106,7 @@ class TestDINRelay < Test::Unit::TestCase
105
106
  assert_equal value, sensors.send('name'+num.to_s).read
106
107
  assert_path '/index.htm', feedback[:uri]
107
108
  end
109
+ assert_equal 1, feedback[:nrequests], "dinrelay request caching not working"
108
110
  end
109
111
  end
110
112
 
@@ -121,6 +123,30 @@ class TestDINRelay < Test::Unit::TestCase
121
123
  end
122
124
  end
123
125
 
126
+ # Test that write invalidates any caching
127
+ def test_write_read_sensors
128
+ sensors = SAAL::Sensors.new(TEST_SENSORS_DINRELAY_FILE, TEST_DBCONF)
129
+ with_webrick(:html=>create_index_html(@vals)) do |feedback|
130
+ @vals.each do |num, state|
131
+ sensors.send('name'+num.to_s).write(0.0)
132
+ sensors.send('name'+num.to_s).read
133
+ end
134
+ assert_equal 16, feedback[:nrequests], "dinrelay caching too much"
135
+ end
136
+ end
137
+
138
+ # Test that the cache times out
139
+ def test_cache_invalidation
140
+ sensors = SAAL::Sensors.new(TEST_SENSORS_DINRELAY_FILE, TEST_DBCONF)
141
+ @og.cache_timeout = 0.1
142
+ with_webrick(:html=>create_index_html(@vals)) do |feedback|
143
+ @og.state(1)
144
+ sleep 0.2
145
+ @og.state(1)
146
+ assert_equal 2, feedback[:nrequests], "dinrelay caching not invalidating"
147
+ end
148
+ end
149
+
124
150
  def test_failed_connection
125
151
  @vals.each do |num, state|
126
152
  assert_equal nil, @og.state(num)
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: saal
3
3
  version: !ruby/object:Gem::Version
4
- hash: 13
4
+ hash: 11
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 2
9
- - 13
10
- version: 0.2.13
9
+ - 14
10
+ version: 0.2.14
11
11
  platform: ruby
12
12
  authors:
13
13
  - "Pedro C\xC3\xB4rte-Real"
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-06-03 00:00:00 -07:00
18
+ date: 2011-06-21 00:00:00 +01:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency