File: sensor.rb

package info (click to toggle)
owfs 3.2p3+dfsg1-2
  • links: PTS, VCS
  • area: main
  • in suites: bullseye, buster
  • size: 8,688 kB
  • sloc: ansic: 65,085; pascal: 5,957; tcl: 2,688; makefile: 1,357; python: 1,114; sh: 891; cs: 623; php: 600; perl: 587; java: 404; ruby: 289; cpp: 105; asm: 102; xml: 53
file content (181 lines) | stat: -rw-r--r-- 5,134 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
module OWNet
  # Exception raised when someone tries to set or query a non-existant
  # OW attribute.
  class AttributeError < RuntimeError
    attr :name
    def initialize(name)
      @name = name
    end
    
    def to_s
      "No such attribute: #{@name}"
    end
  end

  # This class abstracts the OW sensors. Attributes can be set and queried
  # by accessing object attributes. Caching can be enabled and disabled
  # and sensors can be listed and matched against their attributes.
  class Sensor
    include Comparable
    attr_reader :path
  
    # Initialize a sensor for a given path. opts are the same as in 
    # Connection.new. The path is the OW path for the sensor.
    def initialize(path, opts = {})
      if opts[:connection]
        @connection = opts[:connection]
      else
        @connection = Connection.new(opts)
      end

      @attrs = {}

      if path.index('/uncached') == 0
        @path = path['/uncached'.size..-1]
        @path = '/' if path == ''
        @use_cache = false
      else
        @path = path
        @use_cache = true
      end
      
      self.use_cache = @use_cache
    end
    
    private
    # Implements the attributes for the sensor properties by reading and
    # writing them with the current connection.
    def method_missing(name, *args)
      name = name.to_s
      if args.size == 0
        if @attrs.include? name
          @connection.read(@attrs[name])
        else
          raise AttributeError(name)
        end
      elsif name[-1] == "="[0] and args.size == 1
        name = name.to_s[0..-2]
        if @attrs.include? name
          @connection.write(@attrs[name], args[0])
        else
          raise AttributeError(name)
        end
      else
        raise NoMethodError("undefined method \"#{name}\" for #{self}:#{self.class}")
      end
    end
    
    public
    # Converts to a string with the currnet path for the sensor which
    # is different if caching is set to true or false.
    def to_s
      "Sensor(use_path=>\"%s\")" % @use_path
    end
    
    # Compares two sensors. This is implementing by comparing their paths
    # without taking into account caching. Two objects representing 
    # access to the same sensor with and without caching will evaluate
    # as being the same
    def <=>(other)
      self.path <=> other.path
    end
    
    # Implement hash based on the path so that two equal sensors hash to
    # the same value.
    def hash
      self.path.hash
    end
    
    # Sets if owserver's caching is to be used or not.
    def use_cache=(use)
      @use_cache = use
      if use
        @use_path = @path
      else
        @use_path = @path == '/' ? '/uncached' : '/uncached' + @path
      end
      
      if @path == '/'
        @type = @connection.read('/system/adapter/name.0')
      else
        @type = @connection.read("#{@use_path}/type")
      end
      
      @attrs = {}
      self.each_entry {|e| @attrs[e.tr('.','_')] = @use_path + '/' + e}
    end
    
    # Iterates the list of entries for the current path.
    def each_entry
      entries.each {|e| yield e}   
    end
    
    # The list of entries for the current path.
    def entries
      entries = []
      list = @connection.dir(@use_path)
      if @path == '/'
        list.each {|e| entries << e if not e.include? '/'}
      else
        list.each {|e| entries << e.split('/')[-1]}
      end
      entries
    end
    
    # Iterates the list of sensors below the current path.
    def each_sensor(names = ['main', 'aux'])
      self.sensors(names).each {|s| yield s}
    end
    
    # Gives the list of sensors that are below the current path.
    def sensors(names = ['main', 'aux'])
      sensors = []
      if @type == 'DS2409'
        names.each do |branch|
          path = @use_path + '/' + branch
          list = @connection.dir(path).find_all {|e| e.include? '/'}
          list.each do |entry|
            sensors << Sensor.new(entry, :connection => @connection)
          end
        end
      else
        list = @connection.dir(@use_path)
        if @path == '/'
          list.each do |entry|
            if entry.include? '/'
              sensors << Sensor.new(entry, :connection => @connection) 
            end
          end
        end
      end
      sensors
    end
    
    # Check if the sensor has a certain attribute
    def has_attr?(name)
      @attrs.include? name
    end
    
    # Finds the set of children sensors that have a certain ammount of 
    # characteristics. opts should be a hash listing the characteristics
    # to be matched. For example:
    # 
    # #Match all DS18B20 sensors
    # someSensor.find(:type => 'DS18B20')
    #
    # The :all keyword can be set to true or false (default) and find
    # will match as an OR(false) or AND(true) condition.
    def find(opts)
      all = opts.delete(:all)
      
      self.each_sensor do |s|
        match = 0
        opts.each do |name, value| 
          match += 1 if s.has_attr?(name) and s.send(name) == opts[name]
        end
        
        yield s if (!all and match > 0) or (all and match == opts.size)
      end
    end
  end
end