ambient-orb 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/.gitignore +5 -0
- data/Gemfile +8 -0
- data/README.md +31 -0
- data/ambient-orb.gemspec +21 -0
- data/lib/ambient-orb.rb +101 -0
- data/lib/ambient-orb/version.rb +3 -0
- data/spec/lib/ambient-orb_spec.rb +114 -0
- data/spec/spec_helper.rb +13 -0
- metadata +68 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
MzNhZjNlNGY3MDc5ZTA0YTNjMTZkM2Y4Yjc1M2U3MGRhYWMzMzQyYw==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
ODhlYTcyNTM2NGYwNjBlOTgzMmNiNDQyNjc4OTEyMTNjYjc1MWIyYQ==
|
7
|
+
!binary "U0hBNTEy":
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
ZGNiN2IwNTkwNGFkNWE2MmM1MDQ3Njk0MTFjOTY1MjZlNjg0Y2EzNjg4MTJl
|
10
|
+
NDNlM2MxNjVmYzhjYzkzNGFkZGM1NzgxZDUzMzQ0YjBlMDY2Y2M2NmE5Zjcw
|
11
|
+
ZjcwN2UzMzJiOGVhZWNkM2FhY2M0Nzg2MjQ2ZTViOGUzZmFhYzE=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
NmZjNDRlZmZmNGExMjBjNTZhODQ0MGUyMGMzNjIwNTcxNzU1MWUzY2JiNmM3
|
14
|
+
NWI2MDc0OGVhYzlkZDU3NGMxMDIyMGYzODVkNDk2OWU5YTA2MzIyZWM5ZDVm
|
15
|
+
NmJiMjI5YWNmY2EzNzI3N2YyYWQ3M2VjMWNiOGUzYTczYTdkNDA=
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
AmbientOrb
|
2
|
+
===========
|
3
|
+
|
4
|
+
Ruby code to interface with ambientdevices Ambient Orb. Only supports the
|
5
|
+
serial interface as ambientdevices' service no longer exists.
|
6
|
+
|
7
|
+
```ruby
|
8
|
+
require 'ambient-orb'
|
9
|
+
|
10
|
+
# device is automatically detected on OS X
|
11
|
+
orb = AmbientOrb.new
|
12
|
+
|
13
|
+
# a device can be passed manually
|
14
|
+
#orb = AmbientOrb.new(:device => '/dev/ttyS0')
|
15
|
+
|
16
|
+
# a logger can also be passed
|
17
|
+
#orb = AmbientOrb.new(:logger => Logger.new(STDOUT))
|
18
|
+
#orb.logger.level = Logger::DEBUG
|
19
|
+
|
20
|
+
[
|
21
|
+
[ AmbientOrb::COLOR_GREEN, AmbientOrb::ANIMATION_VERY_SLOW ],
|
22
|
+
[ AmbientOrb::COLOR_BLUE, AmbientOrb::ANIMATION_SLOW ],
|
23
|
+
[ AmbientOrb::COLOR_PURPLE, AmbientOrb::ANIMATION_MEDIUM_SLOW ],
|
24
|
+
[ AmbientOrb::COLOR_YELLOW, AmbientOrb::ANIMATION_MEDIUM ],
|
25
|
+
[ AmbientOrb::COLOR_ORANGE, AmbientOrb::ANIMATION_FAST ],
|
26
|
+
[ AmbientOrb::COLOR_RED, AmbientOrb::ANIMATION_VERY_FAST ],
|
27
|
+
].each do |(color, animation)|
|
28
|
+
orb.update(color, animation)
|
29
|
+
sleep(10)
|
30
|
+
end
|
31
|
+
```
|
data/ambient-orb.gemspec
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
|
4
|
+
require 'ambient-orb/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = "ambient-orb"
|
8
|
+
s.version = AmbientOrb::VERSION
|
9
|
+
s.platform = Gem::Platform::RUBY
|
10
|
+
s.authors = ["Jon Tai"]
|
11
|
+
s.email = ["jon.tai@gmail.com"]
|
12
|
+
s.homepage = "https://github.com/jtai/ambient-orb"
|
13
|
+
s.summary = "Ruby code to interface with ambientdevices Ambient Orb"
|
14
|
+
s.description = "Only supports the serial interface as ambientdevices' service no longer exists"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- spec/*`.split("\n")
|
18
|
+
s.require_path = 'lib'
|
19
|
+
|
20
|
+
s.add_runtime_dependency 'serialport', '>= 1.3.1'
|
21
|
+
end
|
data/lib/ambient-orb.rb
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
require 'ambient-orb/version'
|
2
|
+
require 'logger'
|
3
|
+
require 'serialport'
|
4
|
+
|
5
|
+
class AmbientOrb
|
6
|
+
|
7
|
+
# These are fixed characteristics of the orb.
|
8
|
+
SERIAL_PORT_BAUD_RATE = 19200
|
9
|
+
SERIAL_PORT_DATA_BITS = 8
|
10
|
+
SERIAL_PORT_STOP_BITS = 1
|
11
|
+
SERIAL_PORT_PARITY = SerialPort::NONE
|
12
|
+
|
13
|
+
# Colors are specified as an integer from 0 to 36, inclusive. Common colors
|
14
|
+
# are assigned constants for convenience.
|
15
|
+
COLOR_RED = 0
|
16
|
+
COLOR_ORANGE = 3
|
17
|
+
COLOR_YELLOW = 6
|
18
|
+
COLOR_GREEN = 12
|
19
|
+
COLOR_BLUE = 24
|
20
|
+
COLOR_PURPLE = 27
|
21
|
+
|
22
|
+
# Animation is specified as an integer from 0 to 9, inclusive.
|
23
|
+
ANIMATION_NONE = 0
|
24
|
+
ANIMATION_VERY_SLOW = 1
|
25
|
+
ANIMATION_SLOW = 2
|
26
|
+
ANIMATION_MEDIUM_SLOW = 3
|
27
|
+
ANIMATION_MEDIUM = 4
|
28
|
+
ANIMATION_MEDIUM_FAST = 5
|
29
|
+
ANIMATION_FAST = 6
|
30
|
+
ANIMATION_VERY_FAST = 7
|
31
|
+
ANIMATION_CRESCENDO = 8
|
32
|
+
ANIMATION_HEARTBEAT = 9
|
33
|
+
|
34
|
+
def initialize(options = {})
|
35
|
+
@opts = options
|
36
|
+
end
|
37
|
+
|
38
|
+
def device
|
39
|
+
@device ||= begin
|
40
|
+
dev = @opts[:device] || autodetect_device
|
41
|
+
|
42
|
+
unless dev && File.exist?(dev) && File.stat(dev).chardev?
|
43
|
+
raise ArgumentError, 'invalid device'
|
44
|
+
end
|
45
|
+
|
46
|
+
logger.info("selected device #{dev}")
|
47
|
+
|
48
|
+
dev
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def logger
|
53
|
+
@logger ||= begin
|
54
|
+
@opts[:logger] || Logger.new(nil)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def update(color, animation)
|
59
|
+
if (color < 0 || color > 36)
|
60
|
+
raise ArgumentError, 'color must be between 0 and 36'
|
61
|
+
end
|
62
|
+
|
63
|
+
if (animation < 0 || animation > 9)
|
64
|
+
raise ArgumentError, 'animation must be between 0 and 9'
|
65
|
+
end
|
66
|
+
|
67
|
+
logger.info("updating with color=#{color}, animation=#{animation}")
|
68
|
+
|
69
|
+
color_ord = (color + (37 * animation)) / 94 + 32
|
70
|
+
animation_ord = (color + (37 * animation)) % 94 + 32
|
71
|
+
|
72
|
+
send("~A#{color_ord.chr}#{animation_ord.chr}")
|
73
|
+
end
|
74
|
+
|
75
|
+
private
|
76
|
+
|
77
|
+
def autodetect_device
|
78
|
+
devices = Dir.glob('/dev/*.usbmodem*')
|
79
|
+
|
80
|
+
devices.each do |dev|
|
81
|
+
logger.debug("autodetect_device found #{dev}")
|
82
|
+
end
|
83
|
+
|
84
|
+
devices.first
|
85
|
+
end
|
86
|
+
|
87
|
+
def send(command)
|
88
|
+
SerialPort.open(device,
|
89
|
+
SERIAL_PORT_BAUD_RATE,
|
90
|
+
SERIAL_PORT_DATA_BITS,
|
91
|
+
SERIAL_PORT_STOP_BITS,
|
92
|
+
SERIAL_PORT_PARITY) do |serial_port|
|
93
|
+
logger.debug('send "~GT"')
|
94
|
+
serial_port.puts '~GT'
|
95
|
+
|
96
|
+
logger.debug("send \"#{command}\"")
|
97
|
+
serial_port.puts command
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe AmbientOrb do
|
4
|
+
|
5
|
+
let (:options) { {} }
|
6
|
+
let (:orb) { AmbientOrb.new(options) }
|
7
|
+
|
8
|
+
describe '#device' do
|
9
|
+
|
10
|
+
context 'with valid device option' do
|
11
|
+
let (:options) { { :device => '/dev/zero' } }
|
12
|
+
|
13
|
+
it 'returns device' do
|
14
|
+
expect(orb.device).to eq('/dev/zero')
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
context 'with non-existent device' do
|
19
|
+
let (:options) { { :device => '/dev/nosuchdevice' } }
|
20
|
+
|
21
|
+
it 'raises ArgumentError' do
|
22
|
+
expect {
|
23
|
+
orb.device
|
24
|
+
}.to raise_error(ArgumentError)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
context 'with block device' do
|
29
|
+
let (:options) { { :device => `df #{__FILE__} | tail -1 | cut -d ' ' -f 1` } }
|
30
|
+
|
31
|
+
it 'raises ArgumentError' do
|
32
|
+
expect {
|
33
|
+
orb.device
|
34
|
+
}.to raise_error(ArgumentError)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
context 'with autodetected device' do
|
39
|
+
it 'returns first device matching pattern' do
|
40
|
+
expect(Dir).to receive(:glob).and_return(['/dev/urandom', '/dev/random'])
|
41
|
+
expect(orb.device).to eq('/dev/urandom')
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
describe '#update' do
|
48
|
+
|
49
|
+
let (:color) { AmbientOrb::COLOR_RED }
|
50
|
+
let (:animation) { AmbientOrb::ANIMATION_NONE }
|
51
|
+
|
52
|
+
context 'with out of range color' do
|
53
|
+
let (:color) { 37 }
|
54
|
+
|
55
|
+
it 'raises ArgumentError' do
|
56
|
+
expect {
|
57
|
+
orb.update(color, animation)
|
58
|
+
}.to raise_error(ArgumentError)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
context 'with out of range animation' do
|
63
|
+
let (:animation) { 10 }
|
64
|
+
|
65
|
+
it 'raises ArgumentError' do
|
66
|
+
expect {
|
67
|
+
orb.update(color, animation)
|
68
|
+
}.to raise_error(ArgumentError)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
context 'with valid arguments' do
|
73
|
+
it 'sends correct update' do
|
74
|
+
expect(orb).to receive(:send).with('~A ')
|
75
|
+
orb.update(color, animation)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
context 'with purple color' do
|
80
|
+
let (:color) { AmbientOrb::COLOR_PURPLE }
|
81
|
+
|
82
|
+
it 'sends correct update' do
|
83
|
+
expect(orb).to receive(:send).with('~A ;')
|
84
|
+
orb.update(color, animation)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
context 'with fast animation' do
|
89
|
+
let (:animation) { AmbientOrb::ANIMATION_FAST }
|
90
|
+
|
91
|
+
it 'sends correct update' do
|
92
|
+
expect(orb).to receive(:send).with('~A"B')
|
93
|
+
orb.update(color, animation)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
98
|
+
|
99
|
+
describe '#send' do
|
100
|
+
|
101
|
+
let (:options) { { :device => '/dev/zero' } }
|
102
|
+
let (:io) { IO.new }
|
103
|
+
|
104
|
+
it 'sends commands' do
|
105
|
+
io = double('serial_port')
|
106
|
+
expect(io).to receive(:puts).with('~GT')
|
107
|
+
expect(io).to receive(:puts).with('~A ')
|
108
|
+
expect(SerialPort).to receive(:open).and_yield(io)
|
109
|
+
orb.update(AmbientOrb::COLOR_RED, AmbientOrb::ANIMATION_NONE)
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ambient-orb
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jon Tai
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-12-16 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: serialport
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ! '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 1.3.1
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ! '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 1.3.1
|
27
|
+
description: Only supports the serial interface as ambientdevices' service no longer
|
28
|
+
exists
|
29
|
+
email:
|
30
|
+
- jon.tai@gmail.com
|
31
|
+
executables: []
|
32
|
+
extensions: []
|
33
|
+
extra_rdoc_files: []
|
34
|
+
files:
|
35
|
+
- .gitignore
|
36
|
+
- Gemfile
|
37
|
+
- README.md
|
38
|
+
- ambient-orb.gemspec
|
39
|
+
- lib/ambient-orb.rb
|
40
|
+
- lib/ambient-orb/version.rb
|
41
|
+
- spec/lib/ambient-orb_spec.rb
|
42
|
+
- spec/spec_helper.rb
|
43
|
+
homepage: https://github.com/jtai/ambient-orb
|
44
|
+
licenses: []
|
45
|
+
metadata: {}
|
46
|
+
post_install_message:
|
47
|
+
rdoc_options: []
|
48
|
+
require_paths:
|
49
|
+
- lib
|
50
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - ! '>='
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: '0'
|
60
|
+
requirements: []
|
61
|
+
rubyforge_project:
|
62
|
+
rubygems_version: 2.0.0
|
63
|
+
signing_key:
|
64
|
+
specification_version: 4
|
65
|
+
summary: Ruby code to interface with ambientdevices Ambient Orb
|
66
|
+
test_files:
|
67
|
+
- spec/lib/ambient-orb_spec.rb
|
68
|
+
- spec/spec_helper.rb
|