integrity-nabaztag 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile ADDED
@@ -0,0 +1,13 @@
1
+ begin
2
+ require 'jeweler'
3
+ Jeweler::Tasks.new do |gemspec|
4
+ gemspec.name = "integrity-nabaztag"
5
+ gemspec.summary = "A Nabaztag notifier for integrity"
6
+ gemspec.description = "A Nabaztag notifier for integrity"
7
+ gemspec.email = "daniel@collectiveidea.com"
8
+ gemspec.homepage = "http://github.com/collectiveidea/integrity-nabaztag"
9
+ gemspec.authors = ["Daniel Morrison"]
10
+ end
11
+ rescue LoadError
12
+ puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
13
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
@@ -0,0 +1,8 @@
1
+ %p.normal
2
+ %label{ :for => "nabaztag_mac" } MAC Address
3
+ %input.text#nabaztag_mac{ :name => "notifiers[Nabaztag][mac]", :type => "text", :value => config["mac"] }
4
+
5
+ %p.normal
6
+ %label{ :for => "nabaztab_token" } Token
7
+ %input.text#nabaztab_token{ :name => "notifiers[Nabaztag][token]", :type => "text", :value => config["token"] }
8
+
@@ -0,0 +1,37 @@
1
+ require 'integrity'
2
+ $:.unshift(File.dirname(__FILE__) + '/../../../vendor/nabaztag-ruby/lib')
3
+ require 'nabaztag'
4
+
5
+ module Integrity
6
+ class Notifier
7
+ class Nabaztag < Notifier::Base
8
+ attr_reader :config
9
+
10
+ def self.to_haml
11
+ File.read File.dirname(__FILE__) / "config.haml"
12
+ end
13
+
14
+ def deliver!
15
+ nabaztag.voice = 'US-Liberty'
16
+ nabaztag.say(message)
17
+ if commit.failed?
18
+ nabaztag.move_ears(10, 10)
19
+ else
20
+ nabaztag.move_ears(0, 0)
21
+ end
22
+ nabaztag.send
23
+ end
24
+
25
+ private
26
+ def nabaztag
27
+ @nabaztag ||= ::Nabaztag.new(config['mac'], config['token'])
28
+ end
29
+
30
+ def message
31
+ "Build of #{commit.project.name} #{commit.successful? ? "was successful" : "failed"}"
32
+ end
33
+ end
34
+
35
+ register Nabaztag
36
+ end
37
+ end
@@ -0,0 +1 @@
1
+ pkg/Nabaztag-0.3.1.gem
@@ -0,0 +1,18 @@
1
+ = Changes
2
+
3
+ == 0.3.0
4
+
5
+ * Understands new XML responses from API
6
+ * Significant refactoring of response handling
7
+
8
+ == 0.2.0
9
+
10
+ * Version 2 API support
11
+ * Can speak French or English
12
+ * Added command-line utility, nabaztag-say
13
+ * Added gem
14
+
15
+ == 0.1
16
+
17
+ * Initial release
18
+ * Version 1 API only
@@ -0,0 +1,22 @@
1
+ = Nabaztag
2
+
3
+ == About
4
+
5
+ Nabaztag communication library for Ruby.
6
+
7
+ The Nabaztag is a small electronic rabbit with lights, motorised ears, and speech.
8
+
9
+ http://www.nabaztag.com/
10
+
11
+ == Copying
12
+
13
+ Copyright Revieworld Ltd. 2006
14
+
15
+ You may use, copy and redistribute this library under the same terms as Ruby itself
16
+ (http://www.ruby-lang.org/en/LICENSE.txt).
17
+
18
+ == Installation
19
+
20
+ To install (requires root/admin privileges):
21
+
22
+ # ruby setup.rb
@@ -0,0 +1,49 @@
1
+ require "rubygems"
2
+ require "rake/gempackagetask"
3
+ require "zlib"
4
+ require "rake/clean"
5
+
6
+ CLEAN.include("doc", "pkg")
7
+
8
+ SOURCES = FileList["lib/**/*.rb"]
9
+
10
+ spec = Gem::Specification.new do |s|
11
+ s.name = "Nabaztag"
12
+ s.version = "0.3.1"
13
+ s.author = "Paul Battley"
14
+ s.email = "paulbattley@reevoo.com"
15
+ s.summary = "Nabaztag communication library for Ruby."
16
+ s.files = SOURCES
17
+ s.require_path = "lib"
18
+ s.autorequire = "nabaztag"
19
+ s.has_rdoc = true
20
+ s.extra_rdoc_files = %w[README CHANGES]
21
+ s.executables << "nabaztag-say"
22
+ end
23
+
24
+ task :default => :package
25
+
26
+ Rake::GemPackageTask.new(spec) do |pkg|
27
+ pkg.need_tar_gz = true
28
+ end
29
+
30
+ task :package => %W[
31
+ pkg/#{spec.name}-#{spec.version}.gem
32
+ pkg/#{spec.name}-#{spec.version}.tar.gz
33
+ ] do
34
+ puts "packaged version #{spec.version}"
35
+ end
36
+
37
+ file "doc" => SOURCES + spec.extra_rdoc_files do |t|
38
+ p t.prerequisites
39
+ rm_rf t.name
40
+ sh "rdoc #{t.prerequisites.join(" ")}"
41
+ end
42
+
43
+ task :tag do
44
+ unless (trunk = `svn info`[%r!URL: (.+/trunk)!, 1])
45
+ raise RuntimeError, "Couldn't determine trunk URL"
46
+ end
47
+ tag = trunk.sub(/trunk$/, "tags/#{spec.name.downcase}-#{spec.version}")
48
+ sh "svn cp #{trunk} #{tag} -m \"Automatically tagging version #{spec.version}\""
49
+ end
@@ -0,0 +1,97 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'nabaztag'
4
+ require 'optparse'
5
+ load ENV['HOME'] + '/.nabaztag' rescue nil
6
+
7
+ OPTIONS = {
8
+ :mac => NABAZTAG_MAC,
9
+ :token => NABAZTAG_TOKEN,
10
+ }
11
+
12
+ class NabaztagSay
13
+ def list_voices
14
+ message = nabaztag.new_message
15
+ message.action = :get_voices
16
+ response = message.send
17
+ response.voices.each do |language, voices|
18
+ puts language
19
+ voices.sort.each do |v|
20
+ puts " #{v}"
21
+ end
22
+ end
23
+ end
24
+
25
+ def nabaztag
26
+ @mabaztag ||= Nabaztag.new(OPTIONS[:mac], OPTIONS[:token])
27
+ end
28
+
29
+ def say!(sentence)
30
+ nabaztag.say!(sentence)
31
+ end
32
+
33
+ def voice=(v)
34
+ nabaztag.voice = v
35
+ end
36
+ end
37
+
38
+ n = NabaztagSay.new
39
+
40
+ ARGV.options do |o|
41
+ script_name = File.basename($0)
42
+
43
+ o.set_summary_indent(' ')
44
+ o.banner = "Usage: #{script_name} [OPTIONS] TEXT-TO-SAY"
45
+ o.define_head "Tell Nabaztag to say something."
46
+ o.separator ""
47
+ o.separator "If you create a file in your home directory called .nabaztag"
48
+ o.separator "containing the MAC and API token for your device, like this:"
49
+ o.separator " NABAZTAG_MAC = '00039XXXXXXX'"
50
+ o.separator " NABAZTAG_TOKEN = '1234XXXXXXXXXXX'"
51
+ o.separator "then you need not specify the MAC and token on the command line."
52
+ o.separator ""
53
+ o.separator "Options:"
54
+
55
+ begin
56
+ o.on(
57
+ "-m", "--mac=MAC", String,
58
+ "MAC address of device",
59
+ "Default is NABAZTAG_MAC in ~/.nabaztag"
60
+ ) { |OPTIONS[:mac]| }
61
+ o.on(
62
+ "-t", "--token=TOKEN", String,
63
+ "API token",
64
+ "Default is NABAZTAG_TOKEN in ~/.nabaztag"
65
+ ) { |OPTIONS[:token]| }
66
+ o.on(
67
+ "-v", "--voice=VOICE", String,
68
+ "Voice to use for speech"
69
+ ) { |OPTIONS[:voice]| }
70
+ o.on(
71
+ "-l", "--list-voices",
72
+ "List available voices and exit"
73
+ ) {
74
+ n.list_voices
75
+ exit
76
+ }
77
+ o.separator ""
78
+ o.on_tail("-h", "--help", "Show this help message.") { puts o; exit }
79
+ o.parse!
80
+
81
+ OPTIONS.each do |k,v|
82
+ if !v || v.empty?
83
+ raise RuntimeError, "Missing parameter #{v}"
84
+ end
85
+ end
86
+ if ARGV.empty?
87
+ raise RuntimeError, "Nothing to say"
88
+ end
89
+ rescue StandardError => e
90
+ puts "Error: #{e.message}", ''
91
+ puts o
92
+ exit 1
93
+ end
94
+ end
95
+
96
+ n.voice = OPTIONS[:voice]
97
+ n.say!(ARGV.join(' '))
@@ -0,0 +1,160 @@
1
+ require 'nabaztag/message'
2
+ require 'nabaztag/response'
3
+ require 'nabaztag/choreography'
4
+
5
+ #
6
+ # Nabaztag allows control of the text-to-speech, ear control, and choreography features of
7
+ # Nabaztag devices.
8
+ #
9
+ # To use this library, you need to know the MAC of the device (written on the base) and its
10
+ # API token. The token must be obtained from http://www.nabaztag.com/vl/FR/api_prefs.jsp .
11
+ #
12
+ # The API allows different commands to be dispatched simultaneously; in order to achieve this,
13
+ # this library queues commands until they are sent.
14
+ #
15
+ # E.g.
16
+ # nabaztag = Nabaztag.new(mac, token)
17
+ # nabaztag.say('bonjour') # Nothing sent yet
18
+ # nabaztag.move_ears(4, 4) # Still not sent
19
+ # nabaztag.send # Messages sent
20
+ #
21
+ # This also means that if two conflicting commands are issued without an intervening send,
22
+ # only the latter will be carried out.
23
+ #
24
+ # However, beware! The API doesn't seem to respond well if multiple commands are sent in
25
+ # a short period of time: it can become confused and send erroneous commands to the device.
26
+ #
27
+ # In addition, the choreography command does not seem to play well with other commands: if
28
+ # text-to-speech and choreography are sent in one request, only the speech will get through
29
+ # to the rabbit.
30
+ #
31
+ # With version 2 of the API, it is now possible to specify a voice for the message. The
32
+ # default is determined by the rabbit's language (claire22s for French; heather22k for
33
+ # English). The voice's language overrides that of the rabbit: i.e. a French rabbit will
34
+ # speak in English when told to use an English voice.
35
+ #
36
+ # The known voices are grouped by language in the Nabaztag::VOICES constant, but no attempt
37
+ # is made to validate against this list, as Violet may introduce additional voices in future.
38
+ #
39
+ class Nabaztag
40
+
41
+ class ServiceError < RuntimeError ; end
42
+
43
+ attr_reader :mac, :token, :message
44
+ attr_accessor :voice
45
+
46
+ #
47
+ # Create a new Nabaztag instance to communicate with the device with the given MAC address and
48
+ # service token (see class overview for explanation of token).
49
+ #
50
+ def initialize(mac, token)
51
+ @mac, @token = mac, token
52
+ @message = new_message
53
+ @ear_positions = [nil, nil]
54
+ end
55
+
56
+ #
57
+ # Send all pending messages
58
+ #
59
+ def send
60
+ @message.voice = voice
61
+ response = @message.send
62
+ @message = new_message
63
+ unless response.success?
64
+ raise ServiceError, response.raw
65
+ end
66
+ return response
67
+ end
68
+
69
+ #
70
+ # Send a message immediately to get the ear positions.
71
+ #
72
+ def ear_positions
73
+ ear_message = new_message
74
+ ear_message.ears = 'ok'
75
+ response = ear_message.send
76
+ return [response.left_ear, response.right_ear]
77
+ end
78
+
79
+ #
80
+ # Say text.
81
+ #
82
+ def say(text)
83
+ message.tts = text
84
+ nil
85
+ end
86
+
87
+ #
88
+ # Say text immediately.
89
+ #
90
+ def say!(text)
91
+ say(text)
92
+ send
93
+ end
94
+
95
+ #
96
+ # Make the rabbit bark.
97
+ #
98
+ def bark
99
+ say('ouah ouah')
100
+ nil
101
+ end
102
+
103
+ #
104
+ # Bark immediately.
105
+ #
106
+ def bark!
107
+ bark
108
+ send
109
+ end
110
+
111
+ #
112
+ # Set the position of the left and right ears between 0 and 16. Use nil to avoid moving an ear.
113
+ # Note that these positions are not given in degrees, and that it is not possible to specify the
114
+ # direction of movement. For more precise ear control, use choreography instead.
115
+ #
116
+ def move_ears(left, right)
117
+ message.posleft = left if left
118
+ message.posright = right if right
119
+ nil
120
+ end
121
+
122
+ #
123
+ # Move ears immediately.
124
+ #
125
+ def move_ears!(left, right)
126
+ move_ears(left, right)
127
+ send
128
+ end
129
+
130
+ #
131
+ # Creates a new choreography message based on the actions instructed in the block. The commands
132
+ # are evaluated in the context of a new Choreography instance.
133
+ #
134
+ # E.g.
135
+ # nabaztag.choreography do
136
+ # together { led :middle, :green ; led :left, :red }
137
+ # led :right, :yellow
138
+ # together { led :left, :off ; led :right, :off}
139
+ # ...
140
+ # end
141
+ #
142
+ def choreography(title=nil, &blk)
143
+ message.chortitle = title
144
+ message.chor = Choreography.new(&blk).build
145
+ nil
146
+ end
147
+
148
+ #
149
+ # Creates choreography and sends it immediately.
150
+ #
151
+ def choreography!(title=nil, &blk)
152
+ choreography(title, &blk)
153
+ send
154
+ end
155
+
156
+ def new_message
157
+ return Message.new(mac, token)
158
+ end
159
+
160
+ end
@@ -0,0 +1,119 @@
1
+ class Nabaztag
2
+
3
+ #
4
+ # The Choreography class uses class methods to implement a simple DSL. These build API choreography
5
+ # messages based on instructions to move the ears and light the LEDs.
6
+ #
7
+ class Choreography
8
+
9
+ LED_COLORS = {
10
+ :red => [255, 0, 0],
11
+ :orange => [255, 127, 0],
12
+ :yellow => [255, 255, 0],
13
+ :green => [ 0, 255, 0],
14
+ :blue => [ 0, 0, 255],
15
+ :purple => [255, 0, 255],
16
+ :dim_red => [127, 0, 0],
17
+ :dim_orange => [127, 63, 0],
18
+ :dim_yellow => [127, 127, 0],
19
+ :dim_green => [ 0, 127, 0],
20
+ :dim_blue => [ 0, 0, 127],
21
+ :dim_purple => [127, 0, 127],
22
+ :off => [ 0, 0, 0]
23
+ }
24
+ EARS = {:left => [1], :right => [0], :both => [0,1]}
25
+ LEDS = {:bottom => 0, :left => 1, :middle => 2, :right => 3, :top => 4}
26
+ EAR_DIRECTIONS = {:forward => 0, :backward => 1}
27
+
28
+ def initialize(&blk)
29
+ @messages = []
30
+ @tempo = 10
31
+ @time_stamp = 0
32
+ instance_eval(&blk) if block_given?
33
+ end
34
+
35
+ def build
36
+ return (['%d' % @tempo] + @messages).join(',')
37
+ end
38
+
39
+ #
40
+ # Set the tempo of the choreography in Hz (i.e. events per secod). The default is 10
41
+ # events per second.
42
+ #
43
+ def tempo(t)
44
+ @tempo = t
45
+ end
46
+
47
+ #
48
+ # Move :left, :right, or :both ears to angle degrees (0-180) in direction
49
+ # :forward (default) or :backward.
50
+ #
51
+ def ear(which_ear, angle, direction=:forward)
52
+ direction_number = EAR_DIRECTIONS[direction]
53
+ EARS[which_ear].each do |ear_number|
54
+ append_message('motor', ear_number, angle, 0, direction_number)
55
+ end
56
+ advance
57
+ end
58
+
59
+ #
60
+ # Change colour of an led (:top, :right:, middle, :left, :bottom) to a specified colour.
61
+ # The colour may be specified either as RGB values (0-255) or by using one of the named colours
62
+ # in LED_COLORS.
63
+ #
64
+ # E.g.
65
+ # led :middle, :red
66
+ # led :top, 0, 0, 255
67
+ # led :bottom, :off
68
+ #
69
+ def led(which_led, c1, c2=nil, c3=nil)
70
+ led_number = LEDS[which_led]
71
+ if (c1 && c2 && c3)
72
+ red, green, blue = c1, c2, c3
73
+ else
74
+ red, green, blue = LED_COLORS[c1]
75
+ end
76
+ append_message('led', led_number, red, green, blue)
77
+ advance
78
+ end
79
+
80
+ #
81
+ # Group several actions into a single chronological step via a block.
82
+ #
83
+ # E.g.
84
+ # event { led :top, :yellow ; ear :both, 0 }
85
+ #
86
+ def event(duration=1, &blk)
87
+ length(duration, &blk)
88
+ end
89
+
90
+ alias_method :together, :event
91
+
92
+ #
93
+ # Perform one or more actions for n chronological steps
94
+ #
95
+ # E.g.
96
+ # length 3 do
97
+ # led :top, :red ; led :middle, :yellow
98
+ # end
99
+ #
100
+ def length(duration, &blk)
101
+ old_in_event = @in_event
102
+ @in_event = true
103
+ yield
104
+ @in_event = old_in_event
105
+ advance duration
106
+ end
107
+
108
+ private
109
+
110
+ def append_message(*params)
111
+ @messages << ("%d,%s,%d,%d,%d,%d" % ([@time_stamp] + params))
112
+ end
113
+
114
+ def advance(duration=1)
115
+ @time_stamp += duration unless @in_event
116
+ end
117
+
118
+ end
119
+ end