module EmeterGomDaemon class Node < Gom::Remote::Entry Defaults = { :logfile => '-', :interval => 5, :threshold => 5, # in percent :nagios_port => 9918, :stealth => false, :base_value => 0, :scale_factor => 1.0, } # option precedence is: # 1. commands line options # 2. GOM Sensor node values # 3. built-in Default values (see #Defaults) # def initialize path, options = {} @path = path @options = Defaults.merge(gnode @path).merge(options) puts "options: #{@options.inspect}" redirect_to logfile end def logfile @logfile ||= @options[:logfile] end def interval @interval ||= Integer(@options[:interval]) end def scale_factor @scale_factor ||= Float(@options[:scale_factor]) end def base_value @base_value ||= Float(@options[:base_value]) end def emeter_ip @emeter_ip ||= @options[:emeter_ip] end def nagios_port @nagios_port ||= @options[:nagios_port] end def threshold @threshold ||= Float(@options[:threshold]) end def stealth? @stealth ||= @options[:stealth] end #def run # run_nagios_thread # become visible to nagios # gom_checkin # loop do # begin # tic # rescue Exception => e # callstack = "#{e.backtrace.join "\n "}" # puts " ## #{self} - #{e}\n -> #{callstack}" # ensure # sleep interval # end # end #ensure # stop_nagios_thread #end def tic *args old = @current_value || 0 readout = poll #puts "#{t} :: #{readout.inspect}" _, _, _, @current_value = readout change_in_percent = 100 * (1 - (@current_value / old)).abs return if change_in_percent < threshold t = Time.now val = scale_factor * @current_value + base_value puts "#{t} :: #{@current_value} -> #{val}" connection.write "#{@path}:current_value", val end private def poll # expected: '172.20.10.24;WEBIO-042BFF;Sensor 1 0..50A;0,150 A' line = (open "http://#{emeter_ip}/Single1").read ip, id, name, val = (line.split /;/) [ip, id, name, (val.sub! /,/, '.').to_f] end private def redirect_to logfile (@logfile_fd && @logfile_fd.close) rescue nil puts " -- redirecting stdout/stderr to: #{logfile}" if logfile == '-' if @stdout $stderr, $stdout = @stdout, @stderr end else @stderr, @stdout = $stdout, $stderr @logfile_fd = File.open(logfile, File::WRONLY|File::APPEND|File::CREAT) @logfile_fd.sync = true $stderr = $stdout = @logfile_fd end # first line after redirect puts " -- e-meter daemon logile redirect at #{Time.now}" end # push own ip and monitoring port back to GOM node def gom_checkin if stealth? puts "skipping gom check-in in stealth mode" else @gom.write "#{@sensor_path}:daemon_ip", @gom.callback_ip @gom.write "#{@sensor_path}:nagios_port", nagios_port end end def stop_nagios_thread @nagios_thread or return puts ' -- killing nagios thread...' @nagios_thread.kill @nagios_thread = nil puts ' and gone.' self end def run_nagios_thread @nagios_thread .nil? or (raise "already running!") port = nagios_port @nagios_thread = Thread.new do infinity = Proc.new do |env| [200, {"Content-Type" => "text/plain"}, env.inspect] end puts " -- running nagios server on port: #{port}" Rack::Handler::Mongrel.run infinity, :Port => port end self end # # TODO: The GOM helper stuff is experimental and being tested here. Once # it's prove i'll move it into the gom-script gem # #def gattr name # (Gom::Remote.connection.read "#{@sensor_path}:#{name}.txt") #rescue NameError # nil #end #def gnode path # json = (Gom::Remote.connection.read "#{path}.json") # (JSON.parse json)["node"]["entries"].select do |entry| # # 1. select attribute entries # entry.has_key? "attribute" # end.inject({}) do |h, a| # # 2. make it a key, value list # kv = a["attribute"] # h.update(kv["name"].to_sym => kv["value"]) # end #end end end