artoo 1.6.7 → 1.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/README.md +6 -20
  4. data/artoo.gemspec +7 -7
  5. data/bin/artoo +0 -8
  6. data/examples/ardrone_nav_video_wii.rb +1 -1
  7. data/examples/ardrone_nav_wiiclassic.rb +1 -1
  8. data/examples/ardrone_wiiclassic.rb +1 -1
  9. data/examples/firmata.rb +1 -1
  10. data/examples/firmata_button.rb +1 -1
  11. data/examples/hello_api_multiple.rb +1 -1
  12. data/examples/roomba_wiichuck.rb +1 -1
  13. data/examples/sphero.rb +2 -2
  14. data/examples/sphero_color.rb +1 -1
  15. data/examples/sphero_color_wiichuck.rb +2 -2
  16. data/examples/sphero_cycle.rb +1 -1
  17. data/examples/sphero_messages.rb +1 -1
  18. data/examples/sphero_pebble.rb +42 -0
  19. data/examples/sphero_wiichuck.rb +3 -3
  20. data/examples/test_bot.rb +23 -0
  21. data/examples/wiichuck.rb +1 -1
  22. data/examples/wiiclassic.rb +1 -1
  23. data/lib/artoo/api/api.rb +93 -30
  24. data/lib/artoo/api/device_event_client.rb +15 -10
  25. data/lib/artoo/api/route_helpers.rb +14 -3
  26. data/lib/artoo/connection.rb +8 -5
  27. data/lib/artoo/device.rb +29 -11
  28. data/lib/artoo/drivers/driver.rb +4 -0
  29. data/lib/artoo/drivers/{pinger.rb → ping.rb} +6 -6
  30. data/lib/artoo/interfaces/interface.rb +37 -0
  31. data/lib/artoo/interfaces/ping.rb +17 -0
  32. data/lib/artoo/interfaces/rover.rb +35 -0
  33. data/lib/artoo/master.rb +45 -3
  34. data/lib/artoo/robot.rb +33 -8
  35. data/lib/artoo/utility.rb +10 -0
  36. data/lib/artoo/version.rb +1 -1
  37. data/test/api/api_routes_test.rb +46 -0
  38. data/test/connection_test.rb +2 -2
  39. data/test/device_test.rb +8 -1
  40. data/test/interfaces/interface_test.rb +29 -0
  41. data/test/master_test.rb +13 -7
  42. metadata +32 -28
  43. data/Gemfile.lock +0 -88
  44. data/lib/artoo/commands/bluetooth.rb +0 -74
  45. data/lib/artoo/commands/scan.rb +0 -42
  46. data/lib/artoo/ext/actor.rb +0 -18
  47. data/lib/artoo/ext/timers.rb +0 -41
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 85726811d627d143e771a45cf4b31f9b4aec68fe
4
- data.tar.gz: fc3411db1b7653af24c71eecdaa9334770fc2fb2
3
+ metadata.gz: 3e2af8475fd6bcbc50ddb13d80d3d4c1c47a2d8e
4
+ data.tar.gz: 3ff802dd20f87a526d428bdaf8d66244233ecc99
5
5
  SHA512:
6
- metadata.gz: 1b34f40a3c5fc71fa848f2dcaf556e5195026e1199648d101ef598580d0a95167b8240963fd5b16c207572a31487dae53e27c43ff99e217097f0faf67d1254af
7
- data.tar.gz: 1bd83a61f6d170ebc80a80c2ed89b3c6f67e25866fab55966f752f812e00eba99c6e4be08b5447a820616d50b9a46b6851d7436528bc724382b99db35d24b7f9
6
+ metadata.gz: 3edc56e7a01c5fc920e4e89c6fce98b67a8ae507e7b783599b26e9831fd56b1d1655a79d42251602af1235a6f66ef313b47cc11444320cb7c2ec95e582aca0ba
7
+ data.tar.gz: cb17d7f5f705d318155359101445274669fdd81ab2ee77b627a153ed0392e0dc62ed3880e4222e722922e85c500eaea9e170eebb5de0c0a8faac4f4f4d26e90d
data/.gitignore CHANGED
@@ -12,6 +12,7 @@ spec/reports
12
12
  test/tmp
13
13
  test/version_tmp
14
14
  tmp
15
+ Gemfile.lock
15
16
 
16
17
  # YARD artifacts
17
18
  .yardoc
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- [![Artoo](https://raw.github.com/hybridgroup/artoo/gh-pages/images/artoo-logo.png)](http://artoo.io)
1
+ [![Artoo](https://cdn.rawgit.com/hybridgroup/artoo-site/master/source/images/elements/artoo.png)](http://artoo.io)
2
2
 
3
3
  http://artoo.io/
4
4
 
@@ -243,12 +243,13 @@ The repo with full example of using Artoo for test driven robotics is located at
243
243
 
244
244
  ## CLI
245
245
 
246
- Artoo has a Command Line Interface (CLI) so you can access important features right from the command line.
246
+ Artoo uses the Gort [http://gort.io](http://gort.io) Command Line Interface (CLI) so you can access important features right from the command line. We call it "RobotOps", aka "DevOps For Robotics". You can scan, connect, update device firmware, and more!
247
+
248
+ Artoo also has its own CLI so you can generate new robots, or use its console.
247
249
 
248
250
  ```
249
251
  $ artoo
250
252
  Commands:
251
- artoo connect SUBCOMMAND ...ARGS # Connects to device
252
253
  artoo console ROBOT # Run a robot using the Robi console
253
254
  artoo generate SUBCOMMAND ...ARGS # Generates a new robot or adaptor
254
255
  artoo help [COMMAND] # Describe available commands or one specific command
@@ -257,24 +258,9 @@ Commands:
257
258
  artoo version # Displays the current version
258
259
  ```
259
260
 
260
- ### Connect:
261
-
262
- Artoo makes it a lot easier to connect TCP Socket to Bluetooth and serial port devices using the command line interface:
263
-
264
- ```
265
- $ artoo connect
266
- connect commands:
267
- artoo connect bind [ADDRESS] [NAME] # Binds a Bluetooth device to some connected hardware
268
- artoo connect help [COMMAND] # Describe subcommands or one specific subcommand
269
- artoo connect scan # Scan for connected devices
270
- artoo connect serial [NAME] [PORT] # Connect a serial device to a TCP socket using socat
271
- ```
272
-
273
- You can scan your computer for paired Bluetooth devices, bind them to unix ports, and connect socket to serial interfaces, easily from the command line!
274
-
275
261
  ### Console:
276
262
 
277
- Artoo includes Robi, a console based on [Pry](http://pryrepl.org/) to allow you to interactively debug and control your robot.
263
+ Artoo includes a console based on [Pry](http://pryrepl.org/) to allow you to interactively debug and control your robot.
278
264
 
279
265
  ```
280
266
  $ artoo console ./examples/hello.rb
@@ -333,7 +319,7 @@ If you want to help us with some documentation on the site, you can go to [artoo
333
319
  Need more help? Just want to say "Hello"? Come visit us on IRC freenode #artoo
334
320
 
335
321
  ## Contributing
336
-
322
+ * All active development is in the dev branch. New or updated features must be added to the dev branch. Hotfixes will be considered on the master branch in situations where it does not alter behaviour or features, only fixes a bug.
337
323
  * All patches must be provided under the Apache 2.0 License
338
324
  * Please use the -s option in git to "sign off" that the commit is your work and you are providing it under the Apache 2.0 License
339
325
  * Submit a Github Pull Request to the appropriate branch and ideally discuss the changes with us in IRC.
data/artoo.gemspec CHANGED
@@ -20,13 +20,13 @@ Gem::Specification.new do |s|
20
20
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
21
21
  s.require_paths = ["lib"]
22
22
 
23
- s.add_runtime_dependency 'celluloid', '~> 0.15.0'
24
- s.add_runtime_dependency 'celluloid-io', '~> 0.15.0'
25
- s.add_runtime_dependency 'http', '~> 0.5.0'
26
- s.add_runtime_dependency 'reel', '~> 0.4.0'
27
- s.add_runtime_dependency 'multi_json', '~> 1.6.0'
23
+ s.add_runtime_dependency 'celluloid', '>= 0.16.0.pre'
24
+ s.add_runtime_dependency 'celluloid-io', '>= 0.16.0.pre'
25
+ s.add_runtime_dependency 'http', '~> 0.6.1'
26
+ s.add_runtime_dependency 'reel', '~> 0.5.0'
27
+ s.add_runtime_dependency 'multi_json', '~> 1.10.1'
28
28
  s.add_runtime_dependency 'rake'
29
29
  s.add_runtime_dependency 'pry', '~> 0.9.0'
30
- s.add_runtime_dependency 'thor', '~> 0.18.1'
31
- s.add_runtime_dependency 'robeaux', '~> 0.0.4'
30
+ s.add_runtime_dependency 'thor', '~> 0.19.1'
31
+ s.add_runtime_dependency 'robeaux', '0.2.0'
32
32
  end
data/bin/artoo CHANGED
@@ -6,9 +6,7 @@ require 'artoo/robot'
6
6
  require 'artoo/commands/generate'
7
7
  require 'artoo/commands/commands'
8
8
  require 'artoo/commands/install'
9
- require 'artoo/commands/scan'
10
9
  require 'artoo/commands/socket'
11
- require 'artoo/commands/bluetooth'
12
10
 
13
11
  Celluloid.logger = nil
14
12
 
@@ -39,14 +37,8 @@ module CLI
39
37
  desc "generate <SUBCOMMAND> ...ARGS", "Generates a new robot or adaptor"
40
38
  subcommand "generate", Artoo::Commands::Generate
41
39
 
42
- desc "bluetooth <SUBCOMMAND> ...ARGS", "Scans, pairs and Connects to a bluetooth device"
43
- subcommand "bluetooth", Artoo::Commands::Bluetooth
44
-
45
40
  desc "install <SUBCOMMAND> ...ARGS", "Installs utility programs, like socat"
46
41
  subcommand "install", Artoo::Commands::Install
47
-
48
- desc "scan <type> ...ARGS", "Installs utility programs"
49
- subcommand "scan", Artoo::Commands::Scan
50
42
  end
51
43
  end
52
44
 
@@ -9,7 +9,7 @@ device :nav, :driver => :ardrone_navigation, :connection => :navigation
9
9
  connection :videodrone, :adaptor => :ardrone_video, :port => '192.168.1.1:5555'
10
10
  device :video, :driver => :ardrone_video, :connection => :videodrone
11
11
 
12
- connection :arduino, :adaptor => :firmata, :port => "8023"
12
+ connection :arduino, :adaptor => :firmata, :port => "/dev/ttyACM0" # linux
13
13
  device :classic, :driver => :wiiclassic, :connection => :arduino, :interval => 0.1
14
14
 
15
15
  api :host => '127.0.0.1', :port => '8080'
@@ -6,7 +6,7 @@ device :drone, :driver => :ardrone, :connection => :ardrone
6
6
  connection :navigation, :adaptor => :ardrone_navigation, :port => '192.168.1.1:5554'
7
7
  device :nav, :driver => :ardrone_navigation, :connection => :navigation
8
8
 
9
- connection :arduino, :adaptor => :firmata, :port => "8023"
9
+ connection :arduino, :adaptor => :firmata, :port => "/dev/ttyACM0" # linux
10
10
  device :classic, :driver => :wiiclassic, :connection => :arduino, :interval => 0.1
11
11
 
12
12
  api :host => 'localhost', :port => '8080'
@@ -3,7 +3,7 @@ require 'artoo'
3
3
  connection :ardrone, :adaptor => :ardrone, :port => '192.168.0.43:5556'
4
4
  device :drone, :driver => :ardrone, :connection => :ardrone
5
5
 
6
- connection :arduino, :adaptor => :firmata, :port => "8023"
6
+ connection :arduino, :adaptor => :firmata, :port => "/dev/ttyACM0" #linux
7
7
  device :classic, :driver => :wiiclassic, :connection => :arduino, :interval => 0.1
8
8
 
9
9
  OFFSETS = {
data/examples/firmata.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  require 'artoo'
2
2
 
3
- connection :firmata, :adaptor => :firmata, :port => '127.0.0.1:8023'
3
+ connection :firmata, :adaptor => :firmata, :port => '/dev/ttyACM0' #linux
4
4
  device :board
5
5
  device :led, :driver => :led, :pin => 13
6
6
 
@@ -1,6 +1,6 @@
1
1
  require 'artoo'
2
2
 
3
- connection :arduino, :adaptor => :firmata, :port => '127.0.0.1:8023'
3
+ connection :arduino, :adaptor => :firmata, :port => '/dev/ttyACM0' #linux
4
4
  device :led, :driver => :led, :pin => 13
5
5
  device :button, :driver => :button, :pin => 2
6
6
 
@@ -4,7 +4,7 @@ class HelloRobot < Artoo::Robot
4
4
  connection :loopback1
5
5
  connection :loopback2
6
6
  connection :loopback3
7
- device :pinger, :driver => :pinger
7
+ device :pinger, :driver => :ping
8
8
  device :counter, :driver => :counter
9
9
  device :random, :driver => :random
10
10
  device :passthru1
@@ -3,7 +3,7 @@ require 'artoo'
3
3
  connection :roomba, :adaptor => :roomba, :port => '8023'
4
4
  device :roomba, :driver => :roomba, :connection => :roomba
5
5
 
6
- connection :arduino, :adaptor => :firmata, :port => '8024'
6
+ connection :arduino, :adaptor => :firmata, :port => '/dev/ttyACM0' #linux
7
7
  device :wiichuck, :driver => :wiichuck, :connection => :arduino, :interval => 0.1
8
8
 
9
9
  work do
data/examples/sphero.rb CHANGED
@@ -1,8 +1,8 @@
1
1
  require 'artoo'
2
2
 
3
- connection :sphero, :adaptor => :sphero, :port => '127.0.0.1:4569'
3
+ connection :sphero, :adaptor => :sphero, :port => '/dev/rfcomm0' #linux
4
4
  device :sphero, :driver => :sphero
5
-
5
+
6
6
  work do
7
7
  every(1.seconds) do
8
8
  puts "Rolling..."
@@ -1,6 +1,6 @@
1
1
  require 'artoo'
2
2
 
3
- connection :sphero, :adaptor => :sphero, :port => '127.0.0.1:4569'
3
+ connection :sphero, :adaptor => :sphero, :port => '/dev/rfcomm0' #linux
4
4
  device :sphero, :driver => :sphero
5
5
 
6
6
  work do
@@ -1,9 +1,9 @@
1
1
  require 'artoo'
2
2
 
3
- connection :sphero, :adaptor => :sphero, :port => '127.0.0.1:4569'
3
+ connection :sphero, :adaptor => :sphero, :port => '/dev/rfcomm0' #linux
4
4
  device :sphero, :driver => :sphero
5
5
 
6
- connection :arduino, :adaptor => :firmata, :port => "8023"
6
+ connection :arduino, :adaptor => :firmata, :port => '/dev/ttyACM0' #linux
7
7
  device :wiichuck, :driver => :wiichuck, :connection => :arduino, :interval => 0.1
8
8
 
9
9
  work do
@@ -1,6 +1,6 @@
1
1
  require 'artoo'
2
2
 
3
- connection :sphero, :adaptor => :sphero, :port => '127.0.0.1:4560'
3
+ connection :sphero, :adaptor => :sphero, :port => '/dev/rfcomm0' #linux
4
4
  device :sphero, :driver => :sphero
5
5
 
6
6
  work do
@@ -1,6 +1,6 @@
1
1
  require 'artoo'
2
2
 
3
- connection :sphero, :adaptor => :sphero, :port => '127.0.0.1:4560'
3
+ connection :sphero, :adaptor => :sphero, :port => '/dev/rfcomm0' #linux
4
4
  device :sphero, :driver => :sphero
5
5
 
6
6
  def contact(*args)
@@ -0,0 +1,42 @@
1
+ require 'artoo'
2
+
3
+ connection :sphero, :adaptor => :sphero, :port => '/dev/rfcomm0' #linux
4
+ device :sphero, :driver => :sphero
5
+
6
+ connection :pebble, :adaptor => :pebble
7
+ device :watch, :driver => :pebble, :name => 'pebble'
8
+
9
+ api :host => '0.0.0.0', :port => '8080'
10
+
11
+ name 'pebble'
12
+
13
+ def move_forward
14
+ p 'moving forward'
15
+ sphero.roll 100, 0
16
+ sleep 4
17
+ sphero.stop
18
+ end
19
+
20
+ def move_backward
21
+ p 'moving backward'
22
+ sphero.roll 100, 180
23
+ sleep 4
24
+ sphero.stop
25
+ end
26
+
27
+ def button_push(*data)
28
+ unless data[1].nil?
29
+ case data[1]
30
+ when 'up' then
31
+ move_forward
32
+ when 'select' then
33
+ sphero.set_color(rand(255),rand(255),rand(255))
34
+ when 'down' then
35
+ move_backward
36
+ end
37
+ end
38
+ end
39
+
40
+ work do
41
+ on pebble, :button => :button_push
42
+ end
@@ -1,11 +1,11 @@
1
1
  require 'artoo'
2
2
 
3
- connection :sphero, :adaptor => :sphero, :port => '127.0.0.1:4568'
3
+ connection :sphero, :adaptor => :sphero, :port => '/dev/rfcomm0' #linux
4
4
  device :sphero, :driver => :sphero
5
5
 
6
- connection :arduino, :adaptor => :firmata, :port => "8023"
6
+ connection :arduino, :adaptor => :firmata, :port => '/dev/ttyACM0' #linux
7
7
  device :wiichuck, :driver => :wiichuck, :connection => :arduino, :interval => 0.1
8
-
8
+
9
9
  work do
10
10
  init_settings
11
11
  on wiichuck, :c_button => proc {}
@@ -0,0 +1,23 @@
1
+ require 'artoo/robot'
2
+
3
+ class TestBot < Artoo::Robot
4
+ connection :loopback, port: '/dev/null', test: 'abc'
5
+ device :ping, driver: 'ping', pin: '13', test: 'abc'
6
+
7
+ api host: '127.0.0.1', port: '8080'
8
+
9
+ work do
10
+ every(5) { ping }
11
+ end
12
+
13
+ def hello name
14
+ "Hello, #{name}!"
15
+ end
16
+
17
+ end
18
+
19
+ test_bot = TestBot.new(:name => "TestBot", commands: [:hello])
20
+
21
+ Artoo::Master.add_command(:echo, lambda { |param| param })
22
+
23
+ TestBot.work!([test_bot])
data/examples/wiichuck.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  require 'artoo'
2
2
 
3
- connection :arduino, :adaptor => :firmata, :port => "8023"
3
+ connection :arduino, :adaptor => :firmata, :port => "/dev/tty.ACM0"
4
4
  device :wiichuck, :driver => :wiichuck, :connection => :arduino, :interval => 0.1
5
5
 
6
6
  work do
@@ -1,6 +1,6 @@
1
1
  require 'artoo'
2
2
 
3
- connection :arduino, :adaptor => :firmata, :port => "8023"
3
+ connection :arduino, :adaptor => :firmata, :port => "/dev/ttyACM0" #linux
4
4
  device :classic, :driver => :wiiclassic, :connection => :arduino, :interval => 0.1
5
5
 
6
6
  work do
data/lib/artoo/api/api.rb CHANGED
@@ -7,7 +7,7 @@ module Artoo
7
7
  # Artoo API Server provides an interface to communicate with
8
8
  # master class and retrieve information about robots being
9
9
  # controlled
10
- class Server < Reel::Server
10
+ class Server < Reel::Server::HTTP
11
11
  include RouteHelpers
12
12
 
13
13
  # Create new API server
@@ -19,82 +19,114 @@ module Artoo
19
19
 
20
20
  # Dispatches connection requests
21
21
  def on_connection(connection)
22
- while request = connection.request
22
+ while !connection.current_request && request = connection.request
23
23
  dispatch!(connection, request)
24
- if request.websocket?
25
- connection.detach
26
- return
27
- end
28
24
  end
29
25
  end
30
26
 
27
+ # Retrieve api index
28
+ # @return [JSON] MCP index
29
+ get '/api' do
30
+ robots = master.robots.collect { |r| r.to_hash }
31
+ response = {MCP: {robots: robots, commands: master.commands}}
32
+ MultiJson.dump(response)
33
+ end
34
+
35
+ # Retrieve list of master commands
36
+ # @return [JSON] commands
37
+ get '/api/commands' do
38
+ MultiJson.dump({commands: master.commands})
39
+ end
40
+
41
+ # Execute master command
42
+ # @return [JSON] result
43
+ any '/api/commands/:commandid' do
44
+ result = master.command(@params['commandid'], *command_params)
45
+ MultiJson.dump({result: result})
46
+ end
47
+
31
48
  # Retrieve list of robots
32
49
  # @return [JSON] robots
33
- get '/robots' do
34
- MultiJson.dump(master.robots.collect {|r|r.to_hash})
50
+ get '/api/robots' do
51
+ robots = master.robots.collect {|r|r.to_hash}
52
+ response = {robots: robots}
53
+ MultiJson.dump(response)
35
54
  end
36
55
 
37
56
  # Retrieve robot by id
38
57
  # @return [JSON] robot
39
- get '/robots/:robotid' do
40
- master.robot(@params['robotid']).as_json
58
+ get '/api/robots/:robotid' do
59
+ validate_params!
60
+ MultiJson.dump({robot: @robot.to_hash})
41
61
  end
42
62
 
43
63
  # Retrieve robot commands
44
64
  # @return [JSON] commands
45
- get '/robots/:robotid/commands' do
46
- MultiJson.dump(master.robot(@params['robotid']).commands)
65
+ get '/api/robots/:robotid/commands' do
66
+ validate_params!
67
+ MultiJson.dump({commands: @robot.commands})
47
68
  end
48
69
 
49
70
  # Execute robot command
50
71
  # @return [JSON] command
51
- any '/robots/:robotid/commands/:commandid' do
52
- result = master.robot(@params['robotid']).command(@params['commandid'], *command_params)
72
+ any '/api/robots/:robotid/commands/:commandid' do
73
+ validate_params!
74
+ result = @robot.command(@params['commandid'], *command_params)
53
75
  return MultiJson.dump({'result' => result})
54
76
  end
55
77
 
56
78
  # Retrieve robot devices
57
79
  # @return [JSON] devices
58
- get '/robots/:robotid/devices' do
59
- MultiJson.dump(master.robot_devices(@params['robotid']).each_value.collect {|d| d.to_hash})
80
+ get '/api/robots/:robotid/devices' do
81
+ validate_params!
82
+ devices = @robot.devices.each_value.collect {|d| d.to_hash}
83
+ MultiJson.dump({devices: devices})
60
84
  end
61
85
 
62
86
  # Retrieve robot device
63
87
  # @return [JSON] device
64
- get '/robots/:robotid/devices/:deviceid' do
65
- device(@params['robotid'], @params['deviceid']).as_json
88
+ get '/api/robots/:robotid/devices/:deviceid' do
89
+ validate_params!
90
+ MultiJson.dump({device: @device.to_hash})
66
91
  end
67
92
 
68
93
  # Retrieve robot commands
69
94
  # @return [JSON] commands
70
- get '/robots/:robotid/devices/:deviceid/commands' do
71
- MultiJson.dump(device(@params['robotid'], @params['deviceid']).commands)
95
+ get '/api/robots/:robotid/devices/:deviceid/commands' do
96
+ validate_params!
97
+ MultiJson.dump({commands: @device.commands})
72
98
  end
73
99
 
74
100
  # Execute robot command
75
101
  # @return [JSON] command
76
- any '/robots/:robotid/devices/:deviceid/commands/:commandid' do
77
- result = device(@params['robotid'], @params['deviceid']).command(@params['commandid'], *command_params)
102
+ any '/api/robots/:robotid/devices/:deviceid/commands/:commandid' do
103
+ validate_params!
104
+ result = @device.command(@params['commandid'], *command_params)
78
105
  return MultiJson.dump({'result' => result})
79
106
  end
80
107
 
81
- # Subscribte to robot device events
108
+ # Subscribe to robot device events
82
109
  # @return [nil]
83
- get_ws '/robots/:robotid/devices/:deviceid/events/:eventid' do
84
- DeviceEventClient.new(@req.websocket, device(@params['robotid'], @params['deviceid']).event_topic_name(@params['eventid']))
85
- return nil
110
+ get '/api/robots/:robotid/devices/:deviceid/events/:eventid' do
111
+ validate_params!
112
+ topic = @device.event_topic_name(@params['eventid'])
113
+ DeviceEventClient.new(@connection, topic)
114
+ return
86
115
  end
87
116
 
88
117
  # Retrieve robot connections
89
118
  # @return [JSON] connections
90
- get '/robots/:robotid/connections' do
91
- MultiJson.dump(master.robot_connections(@params['robotid']).each_value.collect {|c| c.to_hash})
119
+ get '/api/robots/:robotid/connections' do
120
+ validate_params!
121
+ connections = @robot.connections.each_value.collect {|c| c.to_hash}
122
+ MultiJson.dump({connections: connections})
92
123
  end
93
124
 
94
125
  # Retrieve robot connection
95
126
  # @return [JSON] connection
96
- get '/robots/:robotid/connections/:connectionid' do
97
- master.robot_connection(@params['robotid'], @params['connectionid']).as_json
127
+ get '/api/robots/:robotid/connections/:connectionid' do
128
+ validate_params!
129
+ MultiJson.dump({connection: @conn.to_hash})
98
130
  end
99
131
 
100
132
  protected
@@ -107,6 +139,37 @@ module Artoo
107
139
  master.robot_device(robot_id, device_id)
108
140
  end
109
141
 
142
+ def validate_params!
143
+ robot = @params['robotid']
144
+ device = @params['deviceid']
145
+ connection = @params['connectionid']
146
+
147
+
148
+ if robot
149
+ @robot = master.robot(robot)
150
+ unless @robot
151
+ @error = "No Robot found with the name #{robot}"
152
+ raise RobotNotFound
153
+ end
154
+ end
155
+
156
+ if device
157
+ @device = @robot.devices[device.intern]
158
+ unless @device
159
+ @error = "No device found with the name #{device}"
160
+ raise RobotNotFound
161
+ end
162
+ end
163
+
164
+ if connection
165
+ @conn = @robot.connections[connection.intern]
166
+ unless @conn
167
+ @error = "No connection found with the name #{connection}"
168
+ raise RobotNotFound
169
+ end
170
+ end
171
+ end
172
+
110
173
  def command_params
111
174
  if @req.body.to_s != ""
112
175
  data = MultiJson.load(@req.body.to_s, :symbolize_keys => true)
@@ -2,6 +2,7 @@ require 'json'
2
2
 
3
3
  module Artoo
4
4
  module Api
5
+
5
6
  # The Artoo::Api::DeviceEventClient class is how a websocket client can subscribe
6
7
  # to event notifications for a specific device.
7
8
  # Example: ardrone nav data
@@ -15,22 +16,26 @@ module Artoo
15
16
  # Create new event client
16
17
  # @param [Socket] websocket
17
18
  # @param [String] topic
18
- def initialize(websocket, topic)
19
- @topic = topic
20
- info "Streaming #{@topic} to websocket..."
21
- @socket = websocket
22
- subscribe(@topic, :notify_event)
19
+ def initialize(connection, topic)
20
+ @io = Reel::Response::Writer.new(connection.socket)
21
+
22
+ connection.detach
23
+
24
+ connection.respond(:ok, {
25
+ 'Content-Type' => 'text/event-stream',
26
+ 'Connection' => 'keep-alive',
27
+ 'Transfer-Encoding' => 'chunked',
28
+ 'Cache-Control' => 'no-cache'
29
+ })
30
+
31
+ subscribe(topic, :notify_event)
23
32
  end
24
33
 
25
34
  # Event notification
26
35
  # @param [String] topic
27
36
  # @param [Object] data
28
37
  def notify_event(topic, *data)
29
- # TODO: send which topic sent the notification
30
- @socket << data.last.to_json
31
- rescue Reel::SocketError, Errno::EPIPE
32
- info "Device event notification #{topic} websocket disconnected"
33
- terminate
38
+ @io.write "data: #{JSON.dump(data[0])}\n\n"
34
39
  end
35
40
  end
36
41
  end
@@ -139,16 +139,25 @@ module Artoo
139
139
  try_static! connection, req
140
140
  route! connection, req
141
141
  end
142
+
143
+ return unless connection.response_state == :headers
144
+
142
145
  if resp && !resp.nil?
143
- return if req.websocket?
144
146
  status, body = resp
147
+
145
148
  begin
146
- req.respond status, body
149
+ if @is_static
150
+ req.respond status, body
151
+ else
152
+ req.respond status, {'Content-Type' => 'application/json'}, body
153
+ end
147
154
  rescue Errno::EAGAIN
148
155
  retry
149
156
  end
150
157
  else
151
- req.respond :not_found, "NOT FOUND"
158
+ @error ||= "NOT FOUND"
159
+ req.respond :not_found, {'Content-Type' => 'application/json'}, {error: @error}.to_json
160
+ @error = nil
152
161
  end
153
162
  end
154
163
 
@@ -165,8 +174,10 @@ module Artoo
165
174
  if File.file?(filepath)
166
175
  # TODO: stream this?
167
176
  data = open(filepath).read
177
+ @is_static = true
168
178
  halt :ok, data
169
179
  end
180
+ @is_static = false
170
181
  end
171
182
 
172
183
  def route!(connection, req)