biscuit-monitor 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -0
- data/Gemfile +9 -1
- data/bin/biscuit-monitor +12 -3
- data/bin/console +12 -0
- data/biscuit-monitor.gemspec +5 -2
- data/lib/biscuit-monitor/access_point_scanner.rb +31 -0
- data/lib/biscuit-monitor/cinr.rb +36 -0
- data/lib/biscuit-monitor/cli.rb +20 -0
- data/lib/biscuit-monitor/poller.rb +71 -0
- data/lib/biscuit-monitor/rssi.rb +30 -0
- data/lib/biscuit-monitor/signal_strength.rb +72 -0
- data/lib/biscuit-monitor/version.rb +3 -1
- data/lib/biscuit-monitor.rb +12 -134
- data/lib/migrations/001_create_wi_max_statuses.rb +19 -0
- data/lib/migrations/002_create_wi_fi_access_points.rb +14 -0
- data/log/.gitkeep +0 -0
- data/test/data/airport.plist +1133 -0
- data/tmux_list-windows.txt +1 -0
- metadata +67 -5
data/.gitignore
CHANGED
data/Gemfile
CHANGED
data/bin/biscuit-monitor
CHANGED
@@ -1,8 +1,17 @@
|
|
1
1
|
#!/usr/bin/env ruby -w
|
2
2
|
# encoding: utf-8
|
3
3
|
|
4
|
-
|
4
|
+
trap('SIGINT') { throw :ctrl_c }
|
5
5
|
|
6
|
-
|
6
|
+
catch :ctrl_c do
|
7
|
+
begin
|
8
|
+
$:.unshift(File.dirname(__FILE__) + '/../lib') unless $:.include?(File.dirname(__FILE__) + '/../lib')
|
7
9
|
|
8
|
-
|
10
|
+
require 'biscuit-monitor'
|
11
|
+
|
12
|
+
Biscuit::Monitor::CLI.start
|
13
|
+
rescue SystemExit, Interrupt
|
14
|
+
raise
|
15
|
+
rescue Exception => ex
|
16
|
+
end
|
17
|
+
end
|
data/bin/console
ADDED
data/biscuit-monitor.gemspec
CHANGED
@@ -15,8 +15,11 @@ Gem::Specification.new do |gem|
|
|
15
15
|
gem.require_paths = ["lib"]
|
16
16
|
gem.version = Biscuit::Monitor::VERSION
|
17
17
|
|
18
|
-
gem.add_runtime_dependency '
|
18
|
+
gem.add_runtime_dependency 'colorize'
|
19
19
|
gem.add_runtime_dependency 'multi_json'
|
20
20
|
gem.add_runtime_dependency 'oj'
|
21
|
-
gem.add_runtime_dependency '
|
21
|
+
gem.add_runtime_dependency 'sequel'
|
22
|
+
gem.add_runtime_dependency 'sqlite3'
|
23
|
+
gem.add_runtime_dependency 'thor'
|
24
|
+
gem.add_runtime_dependency 'nokogiri-plist'
|
22
25
|
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Biscuit
|
4
|
+
module Monitor
|
5
|
+
|
6
|
+
require 'nokogiri-plist'
|
7
|
+
|
8
|
+
class AccessPointScanner
|
9
|
+
|
10
|
+
SCAN_ACCESS_POINTS = %x[/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport --scan --xml]
|
11
|
+
|
12
|
+
attr_reader :found_access_points, :scanned_on
|
13
|
+
|
14
|
+
def exec
|
15
|
+
@scanned_on = Time.now.utc
|
16
|
+
|
17
|
+
@found_access_points = raw_found_access_points.map do |access_point|
|
18
|
+
{ ssid: access_point["SSID"].strip, ssid_name: access_point["SSID_STR"], bssid: access_point["BSSID"], rssi: access_point["RSSI"], scanned_on: @scanned_on }
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def raw_found_access_points
|
23
|
+
@raw_found_access_points ||= Nokogiri::PList(SCAN_ACCESS_POINTS)
|
24
|
+
end
|
25
|
+
|
26
|
+
def scan
|
27
|
+
SCAN_ACCESS_POINTS
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'colorize'
|
4
|
+
|
5
|
+
module Biscuit
|
6
|
+
module Monitor
|
7
|
+
class Cinr
|
8
|
+
attr_accessor :level
|
9
|
+
|
10
|
+
def initialize(level)
|
11
|
+
@level = Integer(level)
|
12
|
+
end
|
13
|
+
|
14
|
+
def message
|
15
|
+
"CINR: #{@level}dBs".colorize(foreground_color)
|
16
|
+
end
|
17
|
+
|
18
|
+
def foreground_color
|
19
|
+
case
|
20
|
+
when @level > 24 then
|
21
|
+
:green
|
22
|
+
when (13..24).include?(@level) then
|
23
|
+
:light_green
|
24
|
+
when (8..12).include?(@level) then
|
25
|
+
:yellow
|
26
|
+
when (3..7).include?(@level) then
|
27
|
+
:light_red
|
28
|
+
when @level < 3 then
|
29
|
+
:red
|
30
|
+
else
|
31
|
+
:white
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Biscuit
|
4
|
+
module Monitor
|
5
|
+
|
6
|
+
require 'thor'
|
7
|
+
|
8
|
+
class CLI < Thor
|
9
|
+
default_task :monitor
|
10
|
+
|
11
|
+
desc 'monitor', 'Start monitoring your biscuit.'
|
12
|
+
method_option :device_ip, default: '192.168.1.1', aliases: '-d'
|
13
|
+
method_option :polling_frequency_in_seconds, default: 3, aliases: '-f'
|
14
|
+
|
15
|
+
def monitor
|
16
|
+
Biscuit::Monitor::Poller.new(options[:device_ip], Integer(options[:polling_frequency_in_seconds])).poll
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Biscuit
|
4
|
+
module Monitor
|
5
|
+
class Poller
|
6
|
+
def initialize(device_ip, polling_frequency_in_seconds)
|
7
|
+
@device_ip = device_ip
|
8
|
+
@polling_frequency_in_seconds = polling_frequency_in_seconds
|
9
|
+
end
|
10
|
+
|
11
|
+
def poll
|
12
|
+
until false
|
13
|
+
begin
|
14
|
+
|
15
|
+
ss = SignalStrength.new(@device_ip)
|
16
|
+
ss.exec
|
17
|
+
|
18
|
+
message = ''
|
19
|
+
message << ss.cinr
|
20
|
+
message << ' '
|
21
|
+
message << ss.rssi
|
22
|
+
|
23
|
+
write message
|
24
|
+
|
25
|
+
Thread.new do
|
26
|
+
ap = AccessPointScanner.new
|
27
|
+
ap.exec
|
28
|
+
ap.found_access_points.each do |access_point|
|
29
|
+
DB_CONN[:wi_fi_access_points].insert(access_point)
|
30
|
+
LOGGER.debug(access_point)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
Thread.new(ss.response) do |sig_str|
|
35
|
+
DB_CONN[:wi_max_statuses].insert(sig_str)
|
36
|
+
LOGGER.debug(sig_str)
|
37
|
+
end
|
38
|
+
|
39
|
+
rescue Errno::EHOSTUNREACH => err
|
40
|
+
|
41
|
+
write "Cannot find the biscuit. Check your connection. Tail #{LOG_FILE} for details."
|
42
|
+
LOGGER.error(err.inspect)
|
43
|
+
|
44
|
+
rescue StandardError => err
|
45
|
+
|
46
|
+
write "There was an error talking to your biscuit. Tail #{LOG_FILE} for details."
|
47
|
+
LOGGER.error(err.inspect)
|
48
|
+
|
49
|
+
ensure
|
50
|
+
|
51
|
+
sleep @polling_frequency_in_seconds # TODO when error increase length of time until next check to avoid spamming error log
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
def clear_last_message
|
60
|
+
(@last_message || '').length.times { print "\b" }
|
61
|
+
end
|
62
|
+
|
63
|
+
def write(message)
|
64
|
+
clear_last_message
|
65
|
+
print message
|
66
|
+
@last_message = message
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'colorize'
|
4
|
+
|
5
|
+
module Biscuit
|
6
|
+
module Monitor
|
7
|
+
class Rssi
|
8
|
+
attr_accessor :level
|
9
|
+
|
10
|
+
def initialize(level)
|
11
|
+
@level = Integer(level)
|
12
|
+
end
|
13
|
+
|
14
|
+
def message
|
15
|
+
"RSSI: #{@level}dBs".colorize(foreground_color)
|
16
|
+
end
|
17
|
+
|
18
|
+
def foreground_color
|
19
|
+
case
|
20
|
+
when @level > -50 then
|
21
|
+
:green
|
22
|
+
when @level < -100 then
|
23
|
+
:red
|
24
|
+
else
|
25
|
+
:yellow
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Biscuit
|
4
|
+
module Monitor
|
5
|
+
|
6
|
+
%w< multi_json net/http uri >.each { |dep| require dep }
|
7
|
+
|
8
|
+
class SignalStrength
|
9
|
+
attr_reader :response
|
10
|
+
|
11
|
+
def initialize(device_ip)
|
12
|
+
@device_ip = device_ip
|
13
|
+
end
|
14
|
+
|
15
|
+
def exec
|
16
|
+
@response = parse(parse_javascript_to_json(Net::HTTP.get(device_uri)))[:data]
|
17
|
+
@response.merge!(captured_on: Time.now.utc)
|
18
|
+
end
|
19
|
+
|
20
|
+
def cinr
|
21
|
+
Cinr.new(@response[:cinr]).message
|
22
|
+
end
|
23
|
+
|
24
|
+
def rssi
|
25
|
+
Rssi.new(@response[:rssi]).message
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def device_uri
|
31
|
+
URI.parse("http://#@device_ip/cgi-bin/webmain.cgi?act=act_wimax_status¶m=WIMAX_LINK_STATUS,WIMAX_DEVICE_STATUS")
|
32
|
+
# TODO get the battery status
|
33
|
+
# URI.parse("http://#{@device_ip}/cgi-bin/webmain.cgi?act_battery_status&TYPE=BISCUIT¶m=BATTERY_STATUS")
|
34
|
+
end
|
35
|
+
|
36
|
+
def parse(document)
|
37
|
+
data = {}
|
38
|
+
hash = MultiJson.decode(document, symbolize_keys: true)
|
39
|
+
hash.delete(:list)
|
40
|
+
hash.each do |k, v|
|
41
|
+
data[k] = if v.class == String && /^-?\d+$/ =~ v
|
42
|
+
Integer(v)
|
43
|
+
elsif v.class == Hash
|
44
|
+
idata = {}
|
45
|
+
v.each do |ik, iv|
|
46
|
+
idata[ik] = if iv.class == String && /^-?\d+$/ =~ iv
|
47
|
+
Integer(iv)
|
48
|
+
else
|
49
|
+
iv
|
50
|
+
end
|
51
|
+
end
|
52
|
+
idata
|
53
|
+
else
|
54
|
+
v
|
55
|
+
end
|
56
|
+
end
|
57
|
+
data
|
58
|
+
end
|
59
|
+
|
60
|
+
def parse_javascript_to_json(document)
|
61
|
+
document = document.downcase.split.join
|
62
|
+
document.gsub!(/'/, '"')
|
63
|
+
document.gsub!(/:(\d*),/, ':"\1",')
|
64
|
+
document.gsub!(/(\w*):"/, '"\1":"')
|
65
|
+
document.gsub!(/(\w*):{/, '"\1": {')
|
66
|
+
document.gsub!(/(\w*):\[/, '"\1": [')
|
67
|
+
document.gsub!(/":"/, '": "')
|
68
|
+
document.gsub!(/,/, ', ')
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
data/lib/biscuit-monitor.rb
CHANGED
@@ -1,147 +1,25 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
|
-
require 'biscuit-monitor/version'
|
4
|
-
require 'colorize'
|
5
|
-
require 'logger'
|
6
|
-
require 'multi_json'
|
7
|
-
require 'net/http'
|
8
|
-
require 'thor'
|
9
|
-
require 'uri'
|
10
|
-
|
11
3
|
module Biscuit
|
12
4
|
module Monitor
|
13
|
-
trap("SIGINT") { throw :ctrl_c }
|
14
|
-
|
15
|
-
class Monitor
|
16
|
-
def initialize(device_ip)
|
17
|
-
@logger = Logger.new('biscuit-monitor.log', 10, 1024000)
|
18
|
-
@device_ip = device_ip
|
19
|
-
@seconds = 3
|
20
|
-
end
|
21
|
-
|
22
|
-
def device_uri
|
23
|
-
URI.parse("http://#{@device_ip}/cgi-bin/webmain.cgi?act=act_wimax_status¶m=WIMAX_LINK_STATUS,WIMAX_DEVICE_STATUS")
|
24
|
-
# TODO get the battery status
|
25
|
-
# URI.parse("http://#{@device_ip}/cgi-bin/webmain.cgi?act_battery_status&TYPE=BISCUIT¶m=BATTERY_STATUS")
|
26
|
-
end
|
27
|
-
|
28
|
-
def clear_last_message
|
29
|
-
(@last_message || "").length.times { print "\b" }
|
30
|
-
end
|
31
|
-
|
32
|
-
def cinr_foreground_color(cinr)
|
33
|
-
case
|
34
|
-
when cinr > 24
|
35
|
-
:green
|
36
|
-
when (13..24).include?(cinr)
|
37
|
-
:light_green
|
38
|
-
when (8..12).include?(cinr)
|
39
|
-
:yellow
|
40
|
-
when (3..7).include?(cinr)
|
41
|
-
:light_red
|
42
|
-
when cinr < 3
|
43
|
-
:red
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
def rssi_foreground_color (rssi)
|
48
|
-
case
|
49
|
-
when rssi > -50
|
50
|
-
:green
|
51
|
-
when rssi < -100
|
52
|
-
:red
|
53
|
-
else
|
54
|
-
:yellow
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
def poll
|
59
|
-
catch :ctrl_c do
|
60
|
-
begin
|
61
|
-
response = parse(scrub_response(Net::HTTP.get(device_uri)))
|
62
|
-
|
63
|
-
cinr = Integer(response[:data][:cinr])
|
64
|
-
rssi = Integer(response[:data][:rssi])
|
65
|
-
|
66
|
-
message = "CINR: #{cinr}dBs".colorize(cinr_foreground_color(cinr))
|
67
|
-
message << " ".uncolorize
|
68
|
-
message << "RSSI: #{rssi}dBs".colorize(rssi_foreground_color(rssi))
|
69
|
-
|
70
|
-
write message
|
71
|
-
@logger.debug(response)
|
72
|
-
|
73
|
-
rescue Errno::EHOSTUNREACH => err
|
74
|
-
|
75
|
-
write "Cannot find the biscuit. Check your connection."
|
76
|
-
@logger.error(err.inspect)
|
77
|
-
|
78
|
-
rescue StandardError => err
|
79
|
-
|
80
|
-
write "There was an error checking your biscuit. See the logfile for details."
|
81
|
-
@logger.error(err.inspect)
|
82
|
-
|
83
|
-
ensure
|
84
|
-
|
85
|
-
sleep @seconds # TODO when error increase length of time until next check to avoid spamming error log
|
86
|
-
end until false
|
87
|
-
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
def write(message)
|
92
|
-
clear_last_message
|
93
|
-
print message
|
94
|
-
@last_message = message
|
95
|
-
end
|
96
|
-
|
97
5
|
|
6
|
+
%w< etc logger sequel sqlite3 >.each { |dep| require dep }
|
98
7
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
data[k] = if v.class == String && /^-?\d+$/ =~ v
|
105
|
-
Integer(v)
|
106
|
-
elsif v.class == Hash
|
107
|
-
idata = {}
|
108
|
-
v.each do |ik, iv|
|
109
|
-
idata[ik] = if iv.class == String && /^-?\d+$/ =~ iv
|
110
|
-
Integer(iv)
|
111
|
-
else
|
112
|
-
iv
|
113
|
-
end
|
114
|
-
end
|
115
|
-
idata
|
116
|
-
else
|
117
|
-
v
|
118
|
-
end
|
119
|
-
end
|
120
|
-
data
|
121
|
-
end
|
8
|
+
HOME_DIR = Etc.getpwuid.dir
|
9
|
+
biscuit_monitor_root_dir = "#{HOME_DIR}/.biscuit-monitor"
|
10
|
+
Dir.mkdir(biscuit_monitor_root_dir) unless File.directory?(biscuit_monitor_root_dir)
|
11
|
+
biscuit_monitor_log_dir = "#{biscuit_monitor_root_dir}/log"
|
12
|
+
Dir.mkdir(biscuit_monitor_log_dir) unless File.directory?(biscuit_monitor_log_dir)
|
122
13
|
|
14
|
+
LOG_FILE = "#{biscuit_monitor_log_dir}/biscuit-monitor.log"
|
15
|
+
LOGGER = Logger.new(LOG_FILE, 10, 1024000)
|
123
16
|
|
124
|
-
|
125
|
-
document = document.split.join
|
126
|
-
document.gsub!(/'/, '"')
|
127
|
-
document.gsub!(/:(\d*),/, ':"\1",')
|
128
|
-
document.gsub!(/(\w*):"/, '"\1":"')
|
129
|
-
document.gsub!(/(\w*):{/, '"\1": {')
|
130
|
-
document.gsub!(/(\w*):\[/, '"\1": [')
|
131
|
-
document.gsub!(/":"/, '": "')
|
132
|
-
document.gsub!(/,/, ', ')
|
133
|
-
end
|
17
|
+
DB_CONN = Sequel.sqlite("#{biscuit_monitor_root_dir}/biscuit_monitor.db", loggers: [LOGGER])
|
134
18
|
|
135
|
-
|
19
|
+
Sequel.extension :migration
|
20
|
+
Sequel::Migrator.apply(DB_CONN, File.expand_path(File.dirname(__FILE__)) + '/migrations')
|
136
21
|
|
137
|
-
class CLI < Thor
|
138
|
-
default_task :start
|
139
22
|
|
140
|
-
|
141
|
-
method_option :device_ip, :default => "192.168.1.1", :aliases => "-d"
|
142
|
-
def start
|
143
|
-
Biscuit::Monitor::Monitor.new(options[:device_ip]).poll
|
144
|
-
end
|
145
|
-
end
|
23
|
+
%w< version cinr rssi access_point_scanner poller cli signal_strength >.each { |dep| require "biscuit-monitor/#{dep}" }
|
146
24
|
end
|
147
25
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
Sequel.migration do
|
4
|
+
change do
|
5
|
+
create_table :wi_max_statuses do
|
6
|
+
primary_key :id
|
7
|
+
Integer :cf # 2657000
|
8
|
+
Integer :cinr # 35
|
9
|
+
Integer :rssi # -56
|
10
|
+
Integer :tx_power # -11
|
11
|
+
String :bsid # "00:00:02:26:27:93"
|
12
|
+
String :dev_s # "dataconnected"
|
13
|
+
String :dummy09 # "xx"
|
14
|
+
String :wimax_device_status # "success"
|
15
|
+
String :wimax_link_status # "success"
|
16
|
+
String :captured_on
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/log/.gitkeep
ADDED
File without changes
|