You can probably get the gist as to what this post might be about by the title but it does leave a little to the imagination. For those who hate waiting for the point go ahead an watch this small video…
Before I get right into what I’ve done let me first provide a little background information as to why I’ve done this aside from just looking for “something geeky to do”.
First up I’ve pretty much let everyone know how much I heart Ravello Systems . Not to go too deep but as I build up labs and environments for this blog and for other interests I really like to break things. Why? That’s how I learn best, breaking things, fixing them, then writing them down. The problem is I seem to always be rebuilding or fixing before I can move onto my next project. Ravello solves that issue for me – with Ravello I’m able to keep multiple blueprints of completely configured vSphere labs (different versions, different hardware configs) in the cloud. When I’m feeling geeky I can simply deploy one of these as an application to either Google or Amazon and away I go. If I break it to the point of no return it’s no biggie, I can simply redeploy! Point and case it’s a time-saver for me!
Secondly I love to write code – it’s an odd passion of mine but it’s something I actually went to school for and never 100% pursued. Meaning I love to write code….casually! I couldn’t imagine dedicating my whole career to it, but having the knowledge of how to do it casually sure has helped me with almost every position I’ve held.
Thirdly a little while I ago I purchased a Pebble watch. I’m still not sure why I wanted a smartwatch but I knew if I had one I’d want it to be somewhat “open” and Pebble met those needs. Using a service called CloudPebble and by turning on the development mode on the iPhone app I’m able to deploy custom applications to my Pebble – so that was a big seller when I was looking at watches – oh, and the fact that it’s only like $100 helps as well…
So on to the problem – I mentioned I love Ravello and have multiple applications setup within the service. The applications are great, however it takes a good amount of time after powering one on before you are able to start using it. Those vSphere services need time to initialize and boot. My usual routine involves me logging into Ravello and powering on what I might need for the night before I leave work. That way the initialization can happen during my commute, supper with my family, and bedtime routines and is ready to go when I am. There are times though when I get half way home and realize I forgot to power on my labs, or I’m not near a computer and can’t be bothered to use the small iPhone screen.
There’s an app for that!
For these reasons I decided to try and figure out the Ravello APIs and the Pebble SDK and see if it was possible to create a small application to simply login into Ravello, select an existing application, and power it on! It sounds simple enough but took a lot of trial and error – I had no clue what I was doing but in the end I was left with the solution below – and it works so I guess you could call it a success.
Prerequisites
There’s a few pieces that need to fall into place before any of this will work. First up you wiill need a CloudPebble account. CloudPebble is a development environment that allows us to write applications for use on the Pebble watch in either JavaScript or C. You can use an existing Pebble account to log into CloudPebble or simply setup a new account – either way you need one and it’s free!
Secondly you will need to enable developer connections within the Pebble app on your phone. This is easlily done by selecting ‘Developer’ within the main menu and sliding the switcher over. Honestly, it’s a phone app I’m sure you can figure it out.
Thirdly lets go ahead and setup a project within CloudPebble You can do this by simply importing mine, or manually by giving your new project a name and select PebbleJS as your Project Type. Once created you should be at a screen similar to that shown below…
As you can see we have one source file (app.js). This is the only source file we will need for this project. If you imported my project you are done for now, but if you created a new project manually this file will be full of a bunch of example code on how to perform various functions and respond to different events within the Pebble interface – we won’t need any of this so go ahead and delete all the code within the file, but not the file itself. We will replace it with all of this syntax – explained in the next section.
The code
If you simply just want all the code to go through on your own go head and get that here. For the rest of us I’ll try and explain the different blocks of code below…
1 2 3 4 5 |
// import required libraries var UI = require('ui'); var ajax = require('ajax'); var Vector2 = require('vector2'); var Vibe = require('ui/vibe'); |
Lines 1 through 5 simply deal with importing the libraries we will be working with – UI will give us access to the Pebble UI, Ajax is what we will use for the Ravello API calls, Vector2 for use with positioning on items on the watch, and Vibe is simply so we can access the vibration features of the watch.
1 2 3 |
// setup authentication information var encodedLogin = "mybiglongencodedstring"; var expirationTimeInSeconds = 600; // timeout for app |
Lines 8 and 9 set up a couple of variables for the application. First up, encodedLogin represents a base64 encoded string of the username and password you use to login to Ravello, with a “:” between them. You can grab this by heading to https://www.base64encode.org/ and grabbing the encoded string using UTF-8 as the output – just don’t forget to place the : between (ie. I encoded “mwpreston@myemail.com:supersecretpassword”). Copy the result and place assign it to the encodedLogin variable on Line 8
Line 9 deals with our expiration time – When we power on an application within Ravello we need to specify an auto power off parameter which states how long we want before the application powers itself down. You don’t want to use up all those valuable CPU hours right? The variable defined on line 9 is matched to that, however in seconds so get your calculator out and come up with a number.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
// main window var splashWindow = new UI.Window(); var text = new UI.Text({ position: new Vector2(0,0), size: new Vector2(144,168), text: 'Logging into Ravello Sytems, please wait...', color:'black', textOverflow:'wrap', textAlign:'center', backgroundColor:'white' }); // Add to splashWindow and show splashWindow.add(text); splashWindow.show(); |
Lines 11 through 25 simply define the first splash window we will see in the application. Kind of a message to show the user as we are making the API calls and gathering the application lists. You can start to see some of the Pebble object functions and parameters here…
As we move into ajax calls starting on Line 28 we can start to see the URLs and API calls to Ravello and how they are formatted when using PebbleJS. From here each API call that is sent to Ravello is nested within the previous – this was the only way I could get this to work. You can go ahead and read the docs on the ajax function here – I still don’t really completely understand the values being returned but hey, it works!
Anyways, back to the task at hand – As shown below lines 28-30 makes are login request, passing basic authorization and our encodedLogin variable within the header. After parsing the response on Line 34 we display yet another splash screen (Lines 35-44) with a success.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
//login to Ravello ajax({ url: 'https://cloud.ravellosystems.com/api/v1/login',method: 'post', headers: {Authorization: "Basic " + encodedlogin, Accept: "application/json"} }, function(data,status,obj) { // success into Ravello var contents = JSON.parse(data); var text2 = new UI.Text({ position: new Vector2(0,0), size: new Vector2(144,168), text: 'Hello ' + contents.name + ', you are now logged in! - Fetching applications, please wait...', color:'black', textOverflow:'wrap', textAlign:'center', backgroundColor:'white' }); splashWindow.add(text2); |
Another API call, this one to gather our application lists takes place on lines 46 and 47. From there lines 51 through 74 build a menu to display the application listing, hide our previous screen, and display our newly formed menu.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
ajax({ url: 'https://cloud.ravellosystems.com/api/v1/applications',method: 'get', headers: {Accept: "application/json"} }, function(data,status,obj) { // success application list var apps = JSON.parse(data); var count = Object.keys(apps).length; var menuItems = []; var appname; var appid; for(var i = 0; i < count; i++) { appname = apps[i].name; appid = apps[i].id; menuItems.push({ title:appname, subtitle:appid }); } // Construct Application menu to show to user var resultsMenu = new UI.Menu({ sections: [{ title: 'My Applications', items: menuItems }] }); // Show the Menu, hide the splash resultsMenu.show(); splashWindow.hide(); |
At this point we are waiting on user interaction – the user needs to select the application they want powered on. Line 76 defines that exact event listener, triggered once the user hits the select button.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
// Add an action for SELECT resultsMenu.on('select', function(e) { console.log('Item number ' + e.itemIndex + ' was pressed!'); // this is where magic happens and we translate which item was pressed into turning on applications var detailCard = new UI.Card ( {title: "Starting Lab", subtitle: e.item.title } ); detailCard.show(); detailCard.body('Setting lab power off time to ' + expirationTimeInSeconds.toString() + ' seconds...'); var ExpURL = 'https://cloud.ravellosystems.com/api/v1/applications/'+e.item.subtitle+'/setExpiration'; console.log(ExpURL); // set expiration time for selected application var expbody = { "expirationFromNowSeconds": + expirationTimeInSeconds }; ajax ( { url: ExpURL,type: "json",method: "post",headers: { Accept: "application/json" }, data: expbody }, function(data,status,obj) { // success setting expiration time detailCard.body('Setting lab power off time to ' + expirationTimeInSeconds.toString() + ' seconds...'+ 'DONE!\nPowering on lab...'); var StartURL = 'https://cloud.ravellosystems.com/api/v1/applications/'+e.item.subtitle+'/start'; ajax ( { url: StartURL,type: "json",method:"post",headers: {Accept: "application/json"} }, |
Once an application is selected lines 78 through 84 display some status messages as to what is happening, and beginning on line 89 we start the API calls to power on the application. First (Line 92) sets the expiration time for the selected application. Then, line 102 sends the actual Power Up command to Ravello.
1 2 3 4 5 6 7 |
function(data,status,obj) { // success starting application console.log("Success on start:" + status); detailCard.body('Setting lab power off time to ' + expirationTimeInSeconds.toString() + ' seconds...'+ 'DONE!\nPowering on lab...' + 'DONE!\nLab Powered On' ); Vibe.vibrate('short'); }, |
Lines 108 and 109 simply display some success messages to the user and send a short vibrate command to the Pebble watch.
I’ve done my best to explain the code – it’s probably not the cleanest or best way to do all this but guess what? I can power on a Ravello application from my watch so that’s all that matters… Please feel free to steal all the code if you want it – or here is the complete CloudPebble project if you are in a hurry and just want to skip the copy/paste. I’d love any feedback anyone may have on this. For now this is where the project sits but I’d love to expand it further and integrate with more of the Ravello APIs available. At the moment I’m happy with powering on my Ravello labs from my wrist!
1 thought on “Ravello on my wrist – Pebble in the cloud”