You’ve got a fancy instant espresso coffee maker but you miss talking to your barista? Crisis averted, Ninja Blocks & Twilio are here to help.
NinjaBlocks made this hack as a bit of fun for the recent TwilioCon conference in San Francisco. It might not be 100% practical, however it is a great demonstration of how easy it is to create high-level apps with the Ninja API.
Dial-O-Spresso from ninjablocks on Vimeo.
Lets take a look at how they did it.
The Hardware
They have connected 3 wired relays (made with the the Ninja Breakout Kit) to the buttons of the machine (an Espressi, which is a $79 Nespresso knockoff).
Certainly not the most elegant solution, but it does look cool. Also by using standard relay boards they just pop up on the Ninja dashboard auto-magically when they are plugged in. The developers then used the dashboard widgets to toggle them and figure out which is which so the developers could give them meaningful names.
The Software
Using the Ninja Blocks node library and the Twilio node library there really isn’t much too it. Because its a hack which is just hardcoded Ninja API token (which means no messing with OAuth) and Twilio credentials.
The only slightly tricky part was “pressing” the buttons because the machine uses long presses for programming. You’ll see the developers pressed the buttons for a second to turn it on and make the coffee and for 5 seconds to turn it off.
1. | var ninjaBlocks = require(‘ninja-blocks‘); |
2. | // IMPORTANT – express 2.x must be availailable for the node-twilio lib to work |
3. | var TwilioClient = require(‘twilio‘).Client, |
4. | Twiml = require(‘twilio‘).Twiml; |
5. | |
6. | // Instantiate a Ninja Blocks client – get your _user_access_token from a.ninja.is/hacking |
7. | var ninja = ninjaBlocks.app({user_access_token:‘YOUR_API_TOKEN‘}); |
8. | |
9. | // Instantiate a Twilio client and phone number – note the host must be publicly accessible |
10. | var client = new TwilioClient(‘TWILIO_SID‘, ‘TWILIO_TOKEN‘, ‘HOSTNAME‘); |
11. | var phone = client.getPhoneNumber(‘+14158309667‘); |
12 | |
13. | var STR = { |
14. | POWER : ‘Power‘, |
15. | SHORT : ‘Espresso‘, |
16. | LONG : ‘Long Black‘ |
17. | } |
18. | |
19. | // Fetch our ninja devices |
20. | ninja.devices(function(err,devices) { |
21. | if (err) { |
22. | throw ‘Error fetching devices: “‘+ err.error +‘“‘ |
23. | } else { |
24. | |
25. | // Create a quick map of device name to guid and check that the required relays exist |
26. | var guids = {}; |
27. | Object.keys(devices).forEach(function(guid) { |
28. | guids[devices[guid].shortName] = guid; |
29. | }); |
30. | if (!guids[STR.POWER] || !guids[STR.SHOT] || !guids[STR.LONG]) { |
31. | throw ‘ERROR: You must have relays named “‘+STR.POWER+‘“, “‘+STR.SHORT+‘“, and “‘+STR.LONG+‘“‘ |
32. | } |
33. | |
34. | phone.setup(function(){ |
35. | // Listen for incoming calls |
36. | phone.on(‘incomingCall‘, function(reqParams,res){ |
37. | |
38. | res.append(new Twiml.Say(‘Hi there . . . Coffee is delicious! . . . Would you like a cup?‘)); |
39. | res.append(new Twiml.Pause()); |
40. | |
41. | // Gather a response from callers (times out after 5 seconds) |
42. | var gather = new Twiml.Gather(new Twiml.Say(‘Press 1 for Espresso, Press 2 for Long Black‘)); |
43. | gather.on(‘gathered‘,function(gParams,gRes){ |
44. | var choice = “never enough“; |
45. | if (gParams.Digits == 1){ |
46. | coffee.pour(STR.SHORT); |
47. | } else if (gParams.Digits == 2) { |
48. | coffee.pour(STR.LONG); |
49. | } else { |
50. | choice = “bad for you“; |
51. | } |
52. | // send positive reinforcement |
53. | gRes.append(new Twiml.Say(‘Good choice. Too much coffee is ‘+choice)).send(); |
54. | }); |
55. | // send twiml response to twilio |
56. | res.append(gather).send(); |
57. | }); |
58. | |
59. | }) |
60. | |
61. | var coffee = { |
62. | // using a relay to do a button press requires the relay to be turned on (press |
63. | // down) and turned off (relase). This machine goes into programming mode if the |
64. | // button is held too long, and doesn’t trigger if not pressed long enough |
65. | pressButton : function(relayName, delay) { |
66. | ninja.device(guids[relayName]).actuate(‘1‘); |
67. | setTimeout(function(){ninja.device(guids[relayName]).actuate(‘0‘)},delay); |
68. | }, |
69. | pour : function(coffeeType){ |
70. | // Power up machine with a short press of the power button |
71. | coffee.pressButton(STR.POWER,1000); |
72. | // wait 5 seconds for machine to start then press appropriate coffee button |
73. | setTimeout(function(){ |
74. | coffee.pressButton(coffeeType,1000)} |
75. | ,5000); |
76. | // wait 20 seconds then power down machine with a long press |
77. | setTimeout(function(){ |
78. | coffee.pressButton(STR.POWER,5000)} |
79. | ,25000); |
80. | } |
81. | }; |
82. | |
83. | // Test pour on start |
84. | // coffee.pour(STR.SHORT); |
85. | } |
86. | }); |
1. | { |
2. | “name“: “dial-o-spresso“, |
3. | “author“ : “@askpete“, |
4. | “version“: “0.0.1“, |
5. | “dependencies“: { |
6. | “express“: “2.x“, |
7. | “ninja-blocks“ : “latest“, |
8. | “twilio“ : “latest“ |
9. | } |
10. | } |
I hoped you enjoyed seeing this hack.
Links: