ambient-orb 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 +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
|