bluemoon 0.0.1

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 37873ef2b28838b815a4cd521069a296aa75d663
4
+ data.tar.gz: ccd63c187ed61d588f6440271c45f0174911073d
5
+ SHA512:
6
+ metadata.gz: cb8c7781c38fd2a7317c5a32cea48d1f72dd8198796743a4fc3401a35cd5a62143eb00f8bf5d9dd204e19ead0f006591df8a8590a51ac31a84ee1aec542135b5
7
+ data.tar.gz: c0a3bcdfc95bce2e2152166ba81447ac8dfde0c3dd9e9c81290b8f87143d5c869306e30a05f036392570f7696ba3c6035bd2dd837c7f7ce2d4b1ab2886abe21f
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ The MIT License (MIT)
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,56 @@
1
+ # bluemoon
2
+
3
+ Enable or disable bluetooth on OS X based on your current location
4
+
5
+
6
+ ## Why?
7
+
8
+ I use bluetooth on my Mac at the office for my wireless keyboard and mouse. At home or at the coffee shop, however, I don't use bluetooth at all. So bluetooth is generally running, and:
9
+
10
+ * draining my battery
11
+ * interfering with my wireless connection
12
+
13
+ until I remember to turn it off. And then, of course, I have to turn it back on at the office.
14
+
15
+ Bluemoon will handle powering your MacBook's bluetooth connection based on your location.
16
+
17
+ ## Installation
18
+
19
+ I'm currently working on a homebrew recipe. Until then:
20
+
21
+ ```
22
+ brew install blueutil
23
+ brew install sleepwatcher
24
+ brew install terminal-notifier
25
+ gem install bluemoon --no-wrappers
26
+ ```
27
+
28
+ ## Configuration
29
+
30
+ You'll probably want `bluemoon bootup` to run everytime you reboot:
31
+
32
+ ```
33
+ crontab -e
34
+ @reboot bluemoon bootup
35
+ ```
36
+
37
+ To be useful, you'll need to add at least one location you want Bluetooth enabled.
38
+
39
+ ```
40
+ bluemoon add # current location
41
+ ```
42
+
43
+
44
+ ## TODO
45
+
46
+ * Add IP address or router Mac address support
47
+ * Create a homebrew recipe
48
+ * Vendor `get-location` properly so it installs without the `--no-wrappers` flag
49
+ * Create a homebrew recipe so `brew install bluemoon` works
50
+
51
+
52
+ ## Acknowledgements
53
+
54
+ The [get-location helper](https://github.com/lindes/get-location) was created by @lindes. Thank you.
55
+
56
+ @jonahaaron proposed IP-address support.
data/bin/bluemoon ADDED
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ %w[bluemoon json plist].each do |dependency|
4
+ begin
5
+ require dependency
6
+ rescue LoadError => e
7
+ abort "Unabled to find gem '#{dependency}'. Please run `gem install #{dependency}` to continue."
8
+ end
9
+ end
10
+
11
+ case ARGV.shift
12
+ when 'add' then Bluemoon::Area.add
13
+ when 'bootup' then Bluemoon.bootup
14
+ when 'debug' then Bluemoon::Location.debug
15
+ when 'list' then Bluemoon::Area.list
16
+ when 'open' then Bluemoon::Location.current.open
17
+ when 'remove' then Bluemoon::Area.remove(ARGV.shift)
18
+ when 'run' then Bluemoon.run
19
+ else Bluemoon::Help.show
20
+ end
data/bin/get-location ADDED
Binary file
data/lib/bluemoon.rb ADDED
@@ -0,0 +1,28 @@
1
+ module Bluemoon
2
+ autoload :Area, 'bluemoon/area'
3
+ autoload :Bluetooth, 'bluemoon/bluetooth'
4
+ autoload :Help, 'bluemoon/help'
5
+ autoload :Location, 'bluemoon/location'
6
+ autoload :Notify, 'bluemoon/notify'
7
+
8
+ def self.bootup
9
+ system "sleepwatcher --displaywakeup 'bluemoon run'"
10
+ end
11
+
12
+ def self.run
13
+ # We disable Bluetooth up here,
14
+ # because disabling it helps us connect to wifi faster
15
+ just_disabled = Bluetooth.off
16
+
17
+ if Area.all.any? { |area| area.contains?(Location.current) }
18
+ Bluetooth.on
19
+
20
+ just_disabled or Notify.success('Enabling Bluetooth')
21
+ else
22
+ just_disabled and Notify.success('Disabling Bluetooth')
23
+ end
24
+ rescue
25
+ Bluetooth.on
26
+ Notify.handle($!)
27
+ end
28
+ end
@@ -0,0 +1,50 @@
1
+ module Bluemoon
2
+ class Area < Struct.new(:coordinates)
3
+ PROXIMITY = 400
4
+
5
+ class << self
6
+ def add
7
+ puts "Querying location. This may take a few moments..."
8
+
9
+ File.open(plist_filename, 'w+') do |file|
10
+ file.write [*all, Location.current].map(&:coordinates).uniq.to_plist
11
+ end
12
+
13
+ puts "Added #{Location.current} to list of places to enable bluetooth at."
14
+ puts Location.current.url
15
+ end
16
+
17
+ def all
18
+ Array(Plist::parse_xml(plist_filename)).map do |area|
19
+ self.new(area)
20
+ end
21
+ end
22
+
23
+ def list
24
+ all.each_with_index do |location, i|
25
+ puts "#{(i + 1).to_s.ljust(all.count.to_s.length)}. #{location}"
26
+ end
27
+ end
28
+
29
+ def plist_filename
30
+ "#{ENV['HOME']}/Library/Preferences/com.bluemoon.locations"
31
+ end
32
+
33
+ def remove(i)
34
+ File.open(plist_filename, 'w+') do |file|
35
+ file.write all.tap { |a| a.delete(i.to_i - 1) }
36
+ end
37
+
38
+ list
39
+ end
40
+ end
41
+
42
+ def contains?(location)
43
+ location.distance(coordinates) < PROXIMITY
44
+ end
45
+
46
+ def to_s
47
+ coordinates.join(', ')
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,19 @@
1
+ module Bluemoon
2
+ class Bluetooth
3
+ def self.off
4
+ power(0)
5
+ end
6
+
7
+ def self.on
8
+ power(1)
9
+ end
10
+
11
+ def self.power(flag)
12
+ unless `blueutil power`.to_i == flag.to_i
13
+ `blueutil power #{flag}`
14
+
15
+ true
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,23 @@
1
+ module Bluemoon
2
+ class Help
3
+ def self.show
4
+ puts <<-HELP
5
+
6
+ bluemoon
7
+ Enable or disable bluetooth on OS X based on your current location
8
+
9
+ bootup :: Runs `bluemoon run` whenever your display wakes up.
10
+ add :: Enable bluetooth at your current location
11
+ list :: List all locations where bluetooth is enabled
12
+ remove # :: Remove the numbered location (e.g. `bluemoon remove 3`)
13
+ run :: Enable or disable bluetooth based on your proxmity to the location
14
+
15
+
16
+ debug :: Show current location and meters from office.
17
+ help :: Displays this help message.
18
+ open :: Open your current location in Google Maps
19
+
20
+ HELP
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,72 @@
1
+ module Bluemoon
2
+ class Location < Struct.new(:coordinates)
3
+ class << self
4
+ def current
5
+ @@current ||= self.new(JSON.parse(`get-location -f json`)['coordinates'])
6
+ end
7
+
8
+ def debug
9
+ puts "Querying location. This generally takes 10-20 seconds. Press any key to skip."
10
+
11
+ Thread.new do
12
+ display_debug_message(
13
+ Area.all.join(', '),
14
+ Area::PROXIMITY,
15
+ current.to_s,
16
+ )
17
+
18
+ Kernel.exit
19
+ end
20
+
21
+ if $stdin.gets.length > 0
22
+ display_debug_message(OFFICE.join(', '), PROXIMITY)
23
+ end
24
+ end
25
+
26
+ def display_debug_message(office, proximity, location = 'Skipped', distance = '?', in_range = 'Maybe')
27
+ puts <<-DEBUG
28
+
29
+ Office: #{office}
30
+ Proximity: You must be #{proximity} meters from the office to enable bluetooth.
31
+ Location: #{location}
32
+ Distance: #{distance} meters
33
+ In range: #{in_range}
34
+
35
+ DEBUG
36
+ end
37
+ end
38
+
39
+ # Kindly stolen wholesale from
40
+ # http://stackoverflow.com/a/12969617/615412
41
+ def distance(from)
42
+ a, b = coordinates.dup, from
43
+
44
+ rad_per_deg = Math::PI/180 # PI / 180
45
+ rkm = 6371 # Earth radius in kilometers
46
+ rm = rkm * 1000 # Radius in meters
47
+
48
+ dlon_rad = (b[1]-a[1]) * rad_per_deg # Delta, converted to rad
49
+ dlat_rad = (b[0]-a[0]) * rad_per_deg
50
+
51
+ lat1_rad, lon1_rad = a.map! {|i| i * rad_per_deg }
52
+ lat2_rad, lon2_rad = b.map! {|i| i * rad_per_deg }
53
+
54
+ a = Math.sin(dlat_rad/2)**2 + Math.cos(lat1_rad) * Math.cos(lat2_rad) * Math.sin(dlon_rad/2)**2
55
+ c = 2 * Math.asin(Math.sqrt(a))
56
+
57
+ rm * c # Delta in meters
58
+ end
59
+
60
+ def open
61
+ `open #{url}`
62
+ end
63
+
64
+ def to_s
65
+ "#{coordinates.join(', ')}"
66
+ end
67
+
68
+ def url
69
+ "https://www.google.com/maps/@#{coordinates.join(',')},15z"
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,39 @@
1
+ module Bluemoon
2
+ class Notify
3
+ def self.handle(exception)
4
+ "#{ENV['HOME']}/bluemoon-error-logs.txt".tap do |error_log|
5
+ File.open(error_log, 'a') do |file|
6
+ file.write exception.message
7
+ file.write exception.backtrace.join("\n")
8
+ end
9
+
10
+ Notify.failure(
11
+ "Failed to gather location, enabled bluetooth",
12
+ "-execute 'open #{error_log}'"
13
+ )
14
+ end
15
+
16
+ puts exception.message
17
+ puts *exception.backtrace
18
+ end
19
+
20
+ def self.success(message)
21
+ puts message
22
+
23
+ `terminal-notifier-success \
24
+ -message "#{message}" \
25
+ -title "Bluemoon" \
26
+ -group bluemoon &>/dev/null`
27
+ end
28
+
29
+ def self.failure(message, flags = '')
30
+ puts message
31
+
32
+ `terminal-notifier-failed \
33
+ -message "#{message}" \
34
+ #{flags} \
35
+ -title "Bluemoon" \
36
+ -group bluemoon &>/dev/null`
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,3 @@
1
+ module Bluemoon
2
+ VERSION = '0.0.1'
3
+ end
metadata ADDED
@@ -0,0 +1,99 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: bluemoon
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Nathaniel Jones
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-05-26 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rake
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: json
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: plist
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: Enable or disable bluetooth on OS X based on your current location
56
+ email: nj@third.io
57
+ executables:
58
+ - bluemoon
59
+ - get-location
60
+ extensions: []
61
+ extra_rdoc_files: []
62
+ files:
63
+ - lib/bluemoon/area.rb
64
+ - lib/bluemoon/bluetooth.rb
65
+ - lib/bluemoon/help.rb
66
+ - lib/bluemoon/location.rb
67
+ - lib/bluemoon/notify.rb
68
+ - lib/bluemoon/version.rb
69
+ - lib/bluemoon.rb
70
+ - README.md
71
+ - LICENSE
72
+ - bin/bluemoon
73
+ - bin/get-location
74
+ homepage: http://github.com/nthj/bluemoon
75
+ licenses:
76
+ - MIT
77
+ metadata: {}
78
+ post_install_message:
79
+ rdoc_options: []
80
+ require_paths:
81
+ - lib
82
+ required_ruby_version: !ruby/object:Gem::Requirement
83
+ requirements:
84
+ - - '>='
85
+ - !ruby/object:Gem::Version
86
+ version: '0'
87
+ required_rubygems_version: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - '>='
90
+ - !ruby/object:Gem::Version
91
+ version: '0'
92
+ requirements:
93
+ - blueutil, sleepwatcher, get-location, terminal-notifier
94
+ rubyforge_project:
95
+ rubygems_version: 2.1.11
96
+ signing_key:
97
+ specification_version: 4
98
+ summary: bluemoon
99
+ test_files: []