artoo 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (112) hide show
  1. data/.gitignore +25 -0
  2. data/Gemfile +26 -0
  3. data/Gemfile.lock +144 -0
  4. data/Guardfile +15 -0
  5. data/LICENSE +13 -0
  6. data/README.md +97 -0
  7. data/Rakefile +11 -0
  8. data/api/assets/compass.rb +25 -0
  9. data/api/assets/javascripts/artoo/controllers/robot.js.coffee +27 -0
  10. data/api/assets/javascripts/artoo/routes.js.coffee +23 -0
  11. data/api/assets/javascripts/core.js.coffee +6 -0
  12. data/api/assets/javascripts/vendor/angular.min.js +161 -0
  13. data/api/assets/javascripts/vendor/bootstrap.min.js +6 -0
  14. data/api/assets/javascripts/vendor/jquery.min.js +5 -0
  15. data/api/assets/stylesheets/artoo/_core.css.scss +3 -0
  16. data/api/assets/stylesheets/artoo/_font-awesome.scss +534 -0
  17. data/api/assets/stylesheets/artoo/_variables.scss +8 -0
  18. data/api/assets/stylesheets/core.scss +70 -0
  19. data/api/public/core.css +9848 -0
  20. data/api/public/core.js +259 -0
  21. data/api/public/favicon.ico +0 -0
  22. data/api/public/font/FontAwesome.otf +0 -0
  23. data/api/public/font/fontawesome-webfont.eot +0 -0
  24. data/api/public/font/fontawesome-webfont.svg +284 -0
  25. data/api/public/font/fontawesome-webfont.ttf +0 -0
  26. data/api/public/font/fontawesome-webfont.woff +0 -0
  27. data/api/public/html5shiv.js +8 -0
  28. data/api/public/images/devices/ardrone.jpg +0 -0
  29. data/api/public/images/devices/arduino.jpg +0 -0
  30. data/api/public/images/devices/sphero.png +0 -0
  31. data/api/public/images/glyphicons-halflings-white.png +0 -0
  32. data/api/public/images/glyphicons-halflings.png +0 -0
  33. data/api/public/index.html +36 -0
  34. data/api/public/partials/robot-detail.html +111 -0
  35. data/api/public/partials/robot-device-detail.html +0 -0
  36. data/api/public/partials/robot-index.html +26 -0
  37. data/artoo.gemspec +21 -0
  38. data/bin/retry.sh +8 -0
  39. data/bin/sphero.sh +8 -0
  40. data/examples/ardrone.rb +12 -0
  41. data/examples/ardrone_nav.rb +22 -0
  42. data/examples/ardrone_nav_video.rb +33 -0
  43. data/examples/ardrone_video.rb +22 -0
  44. data/examples/conway_sphero.rb +65 -0
  45. data/examples/firmata.rb +13 -0
  46. data/examples/firmata_button.rb +9 -0
  47. data/examples/hello.rb +12 -0
  48. data/examples/hello_api.rb +9 -0
  49. data/examples/hello_api_multiple.rb +25 -0
  50. data/examples/hello_modular.rb +16 -0
  51. data/examples/hello_multiple.rb +22 -0
  52. data/examples/notifications.rb +9 -0
  53. data/examples/sphero.rb +11 -0
  54. data/examples/sphero_color.rb +13 -0
  55. data/examples/sphero_firmata.rb +17 -0
  56. data/examples/sphero_messages.rb +22 -0
  57. data/examples/sphero_multiple.rb +33 -0
  58. data/examples/wiiclassic.rb +94 -0
  59. data/lib/artoo.rb +3 -0
  60. data/lib/artoo/adaptors/adaptor.rb +54 -0
  61. data/lib/artoo/adaptors/ardrone.rb +32 -0
  62. data/lib/artoo/adaptors/ardrone_navigation.rb +26 -0
  63. data/lib/artoo/adaptors/ardrone_video.rb +27 -0
  64. data/lib/artoo/adaptors/firmata.rb +25 -0
  65. data/lib/artoo/adaptors/loopback.rb +8 -0
  66. data/lib/artoo/adaptors/sphero.rb +46 -0
  67. data/lib/artoo/api.rb +48 -0
  68. data/lib/artoo/api_route_helpers.rb +197 -0
  69. data/lib/artoo/connection.rb +70 -0
  70. data/lib/artoo/delegator.rb +49 -0
  71. data/lib/artoo/device.rb +61 -0
  72. data/lib/artoo/device_event_client.rb +27 -0
  73. data/lib/artoo/drivers/ardrone.rb +9 -0
  74. data/lib/artoo/drivers/ardrone_navigation.rb +21 -0
  75. data/lib/artoo/drivers/ardrone_video.rb +22 -0
  76. data/lib/artoo/drivers/button.rb +40 -0
  77. data/lib/artoo/drivers/driver.rb +48 -0
  78. data/lib/artoo/drivers/led.rb +37 -0
  79. data/lib/artoo/drivers/passthru.rb +9 -0
  80. data/lib/artoo/drivers/pinger.rb +19 -0
  81. data/lib/artoo/drivers/pinger2.rb +18 -0
  82. data/lib/artoo/drivers/sphero.rb +57 -0
  83. data/lib/artoo/drivers/wiichuck.rb +29 -0
  84. data/lib/artoo/drivers/wiiclassic.rb +137 -0
  85. data/lib/artoo/main.rb +32 -0
  86. data/lib/artoo/master.rb +16 -0
  87. data/lib/artoo/port.rb +51 -0
  88. data/lib/artoo/robot.rb +299 -0
  89. data/lib/artoo/utility.rb +39 -0
  90. data/lib/artoo/version.rb +5 -0
  91. data/test/adaptors/adaptor_test.rb +18 -0
  92. data/test/adaptors/ardrone_test.rb +24 -0
  93. data/test/adaptors/firmata_test.rb +25 -0
  94. data/test/adaptors/loopback_test.rb +18 -0
  95. data/test/adaptors/sphero_test.rb +24 -0
  96. data/test/api_test.rb +61 -0
  97. data/test/artoo_test.rb +12 -0
  98. data/test/connection_test.rb +28 -0
  99. data/test/delegator_test.rb +71 -0
  100. data/test/device_test.rb +41 -0
  101. data/test/drivers/ardrone_navigation_test.rb +11 -0
  102. data/test/drivers/ardrone_test.rb +11 -0
  103. data/test/drivers/ardrone_video_test.rb +11 -0
  104. data/test/drivers/driver_test.rb +21 -0
  105. data/test/drivers/led_test.rb +52 -0
  106. data/test/drivers/sphero_test.rb +54 -0
  107. data/test/drivers/wiichuck_test.rb +11 -0
  108. data/test/port_test.rb +33 -0
  109. data/test/robot_test.rb +96 -0
  110. data/test/test_helper.rb +8 -0
  111. data/test/utility_test.rb +27 -0
  112. metadata +185 -0
@@ -0,0 +1,8 @@
1
+ /*
2
+ HTML5 Shiv v3.6.2pre | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed
3
+ */
4
+ (function(l,f){function m(){var a=e.elements;return"string"==typeof a?a.split(" "):a}function i(a){var b=n[a[o]];b||(b={},h++,a[o]=h,n[h]=b);return b}function p(a,b,c){b||(b=f);if(g)return b.createElement(a);c||(c=i(b));b=c.cache[a]?c.cache[a].cloneNode():r.test(a)?(c.cache[a]=c.createElem(a)).cloneNode():c.createElem(a);return b.canHaveChildren&&!s.test(a)?c.frag.appendChild(b):b}function t(a,b){if(!b.cache)b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag();
5
+ a.createElement=function(c){return!e.shivMethods?b.createElem(c):p(c,a,b)};a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+m().join().replace(/\w+/g,function(a){b.createElem(a);b.frag.createElement(a);return'c("'+a+'")'})+");return n}")(e,b.frag)}function q(a){a||(a=f);var b=i(a);if(e.shivCSS&&!j&&!b.hasCSS){var c,d=a;c=d.createElement("p");d=d.getElementsByTagName("head")[0]||d.documentElement;c.innerHTML="x<style>article,aside,figcaption,figure,footer,header,hgroup,nav,section{display:block}mark{background:#FF0;color:#000}</style>";
6
+ c=d.insertBefore(c.lastChild,d.firstChild);b.hasCSS=!!c}g||t(a,b);return a}var k=l.html5||{},s=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,r=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,j,o="_html5shiv",h=0,n={},g;(function(){try{var a=f.createElement("a");a.innerHTML="<xyz></xyz>";j="hidden"in a;var b;if(!(b=1==a.childNodes.length)){f.createElement("a");var c=f.createDocumentFragment();b="undefined"==typeof c.cloneNode||
7
+ "undefined"==typeof c.createDocumentFragment||"undefined"==typeof c.createElement}g=b}catch(d){g=j=!0}})();var e={elements:k.elements||"abbr article aside audio bdi canvas data datalist details figcaption figure footer header hgroup mark meter nav output progress section summary time video",version:"3.6.2pre",shivCSS:!1!==k.shivCSS,supportsUnknownElements:g,shivMethods:!1!==k.shivMethods,type:"default",shivDocument:q,createElement:p,createDocumentFragment:function(a,b){a||(a=f);if(g)return a.createDocumentFragment();
8
+ for(var b=b||i(a),c=b.frag.cloneNode(),d=0,e=m(),h=e.length;d<h;d++)c.createElement(e[d]);return c}};l.html5=e;q(f)})(this,document);
@@ -0,0 +1,36 @@
1
+ <!DOCTYPE html>
2
+ <html ng-app="artoo">
3
+ <head>
4
+ <title>Artoo</title>
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <!-- Bootstrap -->
7
+ <script type="text/javascript" src="core.js"></script>
8
+ <link rel="stylesheet" href="core.css" rel="stylesheet" media="screen">
9
+ <!-- Le HTML5 shim, for IE6-8 support of HTML5 elements -->
10
+ <!--[if lt IE 9]>
11
+ <script src="html5shiv.js"></script>
12
+ <![endif]-->
13
+ </head>
14
+ <body>
15
+ <div class="navbar navbar-inverse navbar-fixed-top">
16
+ <div class="navbar-inner">
17
+ <div class="container">
18
+ <a class="brand" href="/">Artoo</a>
19
+
20
+ <button type="button" class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
21
+ <span class="icon-bar"></span>
22
+ <span class="icon-bar"></span>
23
+ <span class="icon-bar"></span>
24
+ </button>
25
+ <div class="nav-collapse collapse">
26
+ <ul class="nav" ng-app="link">
27
+ <li active-link="active"><a href="#/robots">Robots</a></li>
28
+ </ul>
29
+ </div><!--/.nav-collapse -->
30
+ </div>
31
+ </div>
32
+ </div>
33
+
34
+ <div ng-view></div>
35
+ </body>
36
+ </html>
@@ -0,0 +1,111 @@
1
+ <div class="container">
2
+ <div class="container device">
3
+ <div class="row-fluid">
4
+ <div class="span2">
5
+ <div class="display">
6
+ {{robot.type || "Robot"}}
7
+ </div>
8
+ </div>
9
+ <div class="span10">
10
+ <b>
11
+ <span class="name">{{robot.name}}</span>
12
+ <dl class="controls">
13
+ <dt><i class="icon-fighter-jet"></i> devices: </dt>
14
+ <dd>{{robot.connections.length}}</dd>
15
+ <dt><i class="icon-exchange"></i> connections: </dt>
16
+ <dd>{{robot.connections.length}}</dd>
17
+ </dl>
18
+ </b>
19
+ </div>
20
+ </div>
21
+ </div>
22
+
23
+ <div class="container device details" ng-show='deviceDetail'>
24
+ <div class="row-fluid">
25
+ <div class="span12">
26
+ <!--<div class="display">Pending</div>-->
27
+ <b>
28
+ <span class="name">{{deviceDetail.name}}</span>
29
+ {{device}}
30
+ <dl class="controls">
31
+ <span ng-show='deviceDetail.pin'>
32
+ <dt><i class="icon-fighter-jet"></i> </dt>
33
+ <dd>{{ deviceDetail.pin }}</dd>
34
+ </span>
35
+ <span ng-show='deviceDetail.driver'>
36
+ <dt><i class="icon-exchange"></i></dt>
37
+ <dd>{{ deviceDetail.driver }}</dd>
38
+ </span>
39
+ <span ng-show='deviceDetail.adaptor'>
40
+ <dt><i class="icon-exchange"></i></dt>
41
+ <dd>{{ deviceDetail.adaptor }}</dd>
42
+ </span>
43
+ <span ng-show='deviceDetail.connection'>
44
+ <dt><i class="icon-circle" ng-class="isConnected(deviceDetail.connection)"></i> </dt>
45
+ <dd ng-show="deviceDetail.connection.name">{{deviceDetail.connection.name}}</dd>
46
+ </span>
47
+ </dl>
48
+ </b>
49
+ </div>
50
+ </div>
51
+ <div class="row-fluid content">
52
+ <div class="console">
53
+ <code></code>
54
+ </div>
55
+ </div>
56
+ </div>
57
+
58
+
59
+ <div class="row">
60
+
61
+ <div class="span6">
62
+ <div class="device" ng-repeat="device in robot.devices" ng-click="getDeviceDetail(device.name)">
63
+ <div class="row-fluid">
64
+ <div class="span2">
65
+ <div class="display">
66
+ D
67
+ </div>
68
+ </div>
69
+ <div class="span10">
70
+ <b>
71
+ <span class="name">{{device.name}}</span>
72
+ <dl class="controls">
73
+ <span ng-show="device.pin">
74
+ <dt ><i class="icon-bolt"></i> pin: </dt>
75
+ <dd>{{device.pin}}</dd>
76
+ </span>
77
+ <dt><i class="icon-exchange"></i> </dt>
78
+ <dd>{{device.connection.name}}</dd>
79
+ </dl>
80
+ </b>
81
+ </div>
82
+ </div>
83
+ </div>
84
+ </div>
85
+
86
+
87
+ <div class="span6">
88
+ <div class="device" ng-repeat="connection in robot.connections">
89
+ <div class="row-fluid">
90
+ <div class="span2">
91
+ <div class="display">
92
+ <i class="icon-exchange"></i>
93
+ </div>
94
+ </div>
95
+ <div class="span10">
96
+ <b>
97
+ <span class="name">{{connection.name}}</span>
98
+ <dl class="controls">
99
+ <dt><i class="icon-circle" ng-class="isConnected(connection)"></i> </dt>
100
+ <dd ng-show="connection.port">{{connection.port}}</dd>
101
+ </dl>
102
+ </b>
103
+ </div>
104
+ </div>
105
+ </div>
106
+ </div>
107
+
108
+ </div>
109
+
110
+
111
+ </div>
@@ -0,0 +1,26 @@
1
+ <div class="container">
2
+
3
+ <h1>Listing all Robots</h1>
4
+
5
+ <div class="container device clickable" ng-repeat="robot in robots" ng-click="robotDetail(robot.name)">
6
+ <div class="row-fluid">
7
+ <div class="span2">
8
+ <div class="display sphero">
9
+ {{robot.type || "Robot"}}
10
+ </div>
11
+ </div>
12
+ <div class="span10">
13
+ <b>
14
+ <span class="name">{{robot.name}}</span>
15
+ <dl class="controls">
16
+ <dt><i class="icon-fighter-jet"></i> Devices: </dt>
17
+ <dd>{{robot.connections.length}}</dd>
18
+ <dt><i class="icon-exchange"></i> Connections: </dt>
19
+ <dd>{{robot.connections.length}}</dd>
20
+ </dl>
21
+ </b>
22
+ </div>
23
+ </div>
24
+ </div>
25
+
26
+ </div>
@@ -0,0 +1,21 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "artoo/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "artoo"
7
+ s.version = Artoo::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Ron Evans", "Adrian Zankich", "Ari Lerner", "Mario Ricalde", "Daniel Fischer"]
10
+ s.email = ["artoo@hybridgroup.com"]
11
+ s.homepage = "https://github.com/hybridgroup/artoo"
12
+ s.summary = %q{Ruby-based microframework for robotics}
13
+ s.description = %q{Ruby-based microframework for robotics}
14
+
15
+ s.rubyforge_project = "artoo"
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+ end
@@ -0,0 +1,8 @@
1
+ #!/bin/bash
2
+
3
+ NEXT_WAIT_TIME=0
4
+ COMMAND="socat PIPE:/dev/tty.Sphero-$1-RN-SPP,nonblock TCP-LISTEN:$2,fork"
5
+ until $COMMAND || [ $NEXT_WAIT_TIME -eq 4 ]; do
6
+ echo "retry..."
7
+ sleep $(( NEXT_WAIT_TIME++ ))
8
+ done
@@ -0,0 +1,8 @@
1
+ #!/bin/bash
2
+
3
+ NEXT_WAIT_TIME=0
4
+ COMMAND="socat PIPE:/dev/tty.Sphero-$1-RN-SPP,nonblock TCP-LISTEN:$2,fork"
5
+ until $COMMAND || [ $NEXT_WAIT_TIME -eq 4 ]; do
6
+ echo "retry..."
7
+ sleep $(( NEXT_WAIT_TIME++ ))
8
+ done
@@ -0,0 +1,12 @@
1
+ require 'artoo'
2
+
3
+ connection :ardrone, :adaptor => :ardrone
4
+ device :drone, :driver => :ardrone
5
+
6
+ work do
7
+ drone.start
8
+ drone.take_off
9
+
10
+ after(25.seconds) { drone.hover.land }
11
+ after(30.seconds) { drone.stop }
12
+ end
@@ -0,0 +1,22 @@
1
+ require 'artoo'
2
+
3
+ connection :ardrone, :adaptor => :ardrone, :port => '192.168.1.1:5556'
4
+ device :drone, :driver => :ardrone, :connection => :ardrone
5
+
6
+ connection :navigation, :adaptor => :ardrone_navigation, :port => '192.168.1.1:5554'
7
+ device :nav, :driver => :ardrone_navigation, :connection => :navigation
8
+
9
+ work do
10
+ on nav, :update => :nav_update
11
+ drone.start
12
+ drone.take_off
13
+
14
+ after(25.seconds) { drone.hover.land }
15
+ after(30.seconds) { drone.stop }
16
+ end
17
+
18
+ def nav_update(*data)
19
+ data[1].drone_state.each do |name, val|
20
+ p "#{name}: #{val}"
21
+ end
22
+ end
@@ -0,0 +1,33 @@
1
+ require 'artoo'
2
+
3
+ connection :ardrone, :adaptor => :ardrone, :port => '192.168.1.1:5556'
4
+ device :drone, :driver => :ardrone, :connection => :ardrone
5
+
6
+ connection :navigation, :adaptor => :ardrone_navigation, :port => '192.168.1.1:5554'
7
+ device :nav, :driver => :ardrone_navigation, :connection => :navigation
8
+
9
+ connection :videodrone, :adaptor => :ardrone_video, :port => '192.168.1.1:5555'
10
+ device :video, :driver => :ardrone_video, :connection => :videodrone
11
+
12
+ work do
13
+ on nav, :update => :nav_update
14
+ on video, :frame => :v_frame
15
+
16
+ drone.start
17
+ drone.take_off
18
+
19
+ after(25.seconds) { drone.hover.land }
20
+ after(30.seconds) { drone.stop }
21
+ end
22
+
23
+ def v_frame(*data)
24
+ @count ||= 0
25
+ @count += 1
26
+ puts "Frame# #{@count} #{data[1].size} bytes"
27
+ end
28
+
29
+ def nav_update(*data)
30
+ data[1].drone_state.each do |name, val|
31
+ p "#{name}: #{val}"
32
+ end
33
+ end
@@ -0,0 +1,22 @@
1
+ require 'artoo'
2
+
3
+ connection :ardrone, :adaptor => :ardrone, :port => '192.168.1.1:5556'
4
+ device :drone, :driver => :ardrone, :connection => :ardrone
5
+
6
+ connection :videodrone, :adaptor => :ardrone_video, :port => '192.168.1.1:5555'
7
+ device :video, :driver => :ardrone_video, :connection => :videodrone
8
+
9
+ work do
10
+ on video, :frame => :v_frame
11
+ drone.start
12
+ drone.take_off
13
+
14
+ after(25.seconds) { drone.hover.land }
15
+ after(30.seconds) { drone.stop }
16
+ end
17
+
18
+ def v_frame(*data)
19
+ @count ||= 0
20
+ @count += 1
21
+ puts "Frame# #{@count} #{data[1].size} bytes"
22
+ end
@@ -0,0 +1,65 @@
1
+ require 'artoo/robot'
2
+
3
+ class SpheroRobot < Artoo::Robot
4
+ connection :sphero, :adaptor => :sphero
5
+ device :sphero, :driver => :sphero
6
+
7
+ work do
8
+ birth
9
+
10
+ every(3.seconds) { movement if alive? }
11
+ every(10.seconds) { birthday if alive? }
12
+ end
13
+
14
+ def alive?; (@alive == true); end
15
+
16
+ def birth
17
+ sphero.detect_collisions
18
+ @age = 0
19
+ life
20
+ movement
21
+ end
22
+
23
+ def life
24
+ @alive = true
25
+ sphero.set_color :green
26
+ end
27
+
28
+ def death
29
+ puts "Death."
30
+ @alive = false
31
+ sphero.set_color :red
32
+ sphero.stop
33
+ terminate
34
+ end
35
+
36
+ def birthday
37
+ @age += 1
38
+ contacts = sphero.collisions.size
39
+ sphero.clear_collisions
40
+
41
+ puts "Happy birthday, #{name}, you are #{@age} and had #{contacts} contacts."
42
+ #return if @age <= 3
43
+ death unless contacts >= 3 && contacts < 5
44
+ end
45
+
46
+ def movement
47
+ sphero.roll 90, rand(360)
48
+ end
49
+ end
50
+
51
+ SPHEROS = {"4560" => "/dev/tty.Sphero-BRG-RN-SPP",
52
+ "4561" => "/dev/tty.Sphero-YBW-RN-SPP",
53
+ "4562" => "/dev/tty.Sphero-BWY-RN-SPP",
54
+ "4563" => "/dev/tty.Sphero-YRR-RN-SPP",
55
+ "4564" => "/dev/tty.Sphero-OBG-RN-SPP",
56
+ "4565" => "/dev/tty.Sphero-GOB-RN-SPP",
57
+ "4566" => "/dev/tty.Sphero-PYG-RN-SPP"}
58
+ robots = []
59
+ SPHEROS.each_key {|p|
60
+ robots << SpheroRobot.new(:connections =>
61
+ {:sphero =>
62
+ {:port => p}})
63
+ }
64
+
65
+ SpheroRobot.work!(robots)
@@ -0,0 +1,13 @@
1
+ require 'artoo'
2
+
3
+ connection :firmata, :adaptor => :firmata, :port => '4567' #/dev/tty.usbserial-A700636n'
4
+ device :board
5
+ device :led, :driver => :led, :pin => 13
6
+
7
+ work do
8
+ puts "Firmware name #{board.firmware_name}"
9
+ puts "Firmata version #{board.version}"
10
+ every 1.second do
11
+ led.toggle
12
+ end
13
+ end
@@ -0,0 +1,9 @@
1
+ require 'artoo'
2
+
3
+ connection :arduino, :adaptor => :firmata, :port => '4567'
4
+ device :led, :driver => :led, :pin => 13
5
+ device :button, :driver => :button, :pin => 2
6
+
7
+ work do
8
+ on button, :push => proc {led.toggle}
9
+ end
@@ -0,0 +1,12 @@
1
+ require 'artoo'
2
+
3
+ connection :loop
4
+
5
+ work do
6
+ every(3.seconds) do
7
+ puts "hello"
8
+ end
9
+ after(10.seconds) do
10
+ puts "wow"
11
+ end
12
+ end
@@ -0,0 +1,9 @@
1
+ require 'artoo'
2
+
3
+ connection :loop
4
+ device :passthru
5
+ api :host => '127.0.0.1', :port => '4321'
6
+
7
+ work do
8
+ puts "Hello from the API running at #{api_host}:#{api_port}..."
9
+ end