Hello World for ConnectIQ

I'm going to write a simple Hello World program written in MonkeyC and run it on the simulator.

Setting up the environment

The easiest way to get up and running is to download and install the latest version of Eclipse Luna (I'm using the IDE for Java Developers). The Connect IQ Eclipse plugin and SDK can all be downloaded and installed from within eclipse. Use the following steps to setup your Connect IQ environment.

Installing the Plugin

  • After installation is complete, start up Eclipse.
  • In the top menubar, click on "Help > Install New Software..."
    • Next to the "Work with:" input box click the "Add..." button.
    • Click OK to accept the addition. The "Work with:" box should have updated to your newly added repository. If it didn't, click on the dropdown and select it.
    • In the table below there should be a list of software available within that repository. At this time, there should only be a single item Connect IQ.
    • Click the checkbox next to it. This will install the main IDE and SDK Manager.
    • Click next.
    • If everything looks alright on the next page, then click next again.
    • Accept the terms of agreement and click Finish to go ahead and install the Connect IQ Plugin.
      • Note: During the installation process, a dialog will pop up telling you that the software you're installing is unsigned. I'm sure there's nothing harmful: click OK.
  • After installation completes successfully, you'll need to restart eclipse.

Installing the SDK

  • There should now be a new menu item called "Connect IQ" in the menubar at the top.
  • Click on it and select "Open SDK Manager".
    • A new window will appear showing the SDK versions available. Click the browse button and select where you want to save your SDK.
      • For example, I created mine at C:\connectiq.
    • Press the Download button next to the version of the SDK that you want to work with.
      • I'm currently working with the latest (0.1.1 at this time).
    • A window will pop up asking if you want to set this version as the default version for the SDK.
      • CLICK NO (you should be able to click yes and have the following steps completed automatically, but there appears to be a bug). This has been fixed as of the 0.2.4 SDK release, click Yes.
    • If you're on something older than 0.2.4, then do the following:
      • Click Window > Preferences.
        • Select Connect IQ
        • Click the New button.
        • Browse to where your SDK was saved. In my case, it can be found in C:\connectiq\connectiq-win-0.x.y.z. NOTE do not choose the bin directory.
        • Click OK to save your changes.

Final touches

In the top menubar, click on "Window > Open Perspective > other". Select Connect IQ from the list and hit OK.

Be sure to add the /bin/ directory of the SDK to your PATH for easy command line execution. Using my install setup as an example, my bin directory is C:\connectiq\connectiq-win-x.y.z\bin

That's it! Your environment should be good to go!

Creating a new project

Now that Eclipse is all set with the Connect IQ plugin, creating a new Connect IQ project will automatically create all of the project files that we need in order to get up and running quickly. To do so

  • Click "File > New > Other" from the top menubar.
  • Click the dropdown arrow next to Connect IQ
  • Select Connect IQ Project and click next.
  • Give your project a name (mine is going to be hello) and click next.
  • Select the type of project. For this short example, I'm going to make a Watch Face because it's the simplest thing to make to get something on the screen.
    • If for some reason you don't see any checkboxes under Target Platforms, then your plugin hasn't been setup correctly. Specifically, make sure that the last step under Installing the SDK has been completed correctly.
  • Select your target platforms. I'm picking the Square Watch because Round Watches are for squares :D
  • Finally, click Finish to create your project.

This will create your project's skeletal structure as well as some example code. helloView.mc will automatically be loaded into the text editor ready for some coding.

Running the sample code

At this point, I just want to run the code and see what happens, but before I can do that, I have to set up a Run Configuration first. To do that:

  • Click the down arrow next to the green run arrow in the toolbar at the top.
  • Click Run Configurations
  • Select Connect IQ App
  • Click the New Launch Configuration icon (picture of a piece of paper with a yellow plus).
  • Give the configuration a name, select the project being built, and if you chose to build for something other than a Square Face, select which face style you want to build for.

Now, I need to run the simulator. This can be done in Eclipse by clicking Connect IQ > Start Simulator in the menubar at the top (shortcut: Ctrl + 6).

Then, just click the green Play button to compile and run.


Yay! It shows some number resembling the current hour (in military time!) separated by a colon then the current minute (without zero padding). Let's have a look at the starting code and figure out what's going on.

No matter what you're making for the watch, an app class is always needed. Think of the app class as the entry point that tells the watch how to use your cool new program. When you created the new project through eclipse, a helloApp class was created for you in the file helloApp.mc.

Every module has access to the built-in Toybox namespace which is a container for MonkeyC's standard library. Inside of that namespace is a module named Application. Application is home to the AppBase class which we need to extend in order to create a new app.

using Toybox.Application as App;

The above using statement allows us to bring in the Application module into our current namespace (so we don't have to constantly refer to it as Toybox.Application all over the place) and then, we can use the as keyword to give Application an alias; in this case App.

To create a class in MonkeyC, it requires a name and a body. If the class should inherit from an existing class, the existing modifier should be used followed by the name of the class to inherit from. In order to make an app class that the watch can understand in must inherit from AppBase.

class helloApp extends App.AppBase {
    // ...
}

An app class needs to tell the watch how to start, how to stop and what view to show when it loads. The methods onStart(), onStop(), and getInitialView() tell the app how to do that respectively. The start and stop methods could be used to load/save user data (such as preferences or settings) and can be used again at a later time.

Since we're creating a super simple watch face, I don't care about the onStart() or onStop() methods and so I'm going to remove them as the base App will have just empty methods.4 The only method that is of importance is the getInitialView() method. Its main purpose is to do any initialization and then return an array containing a Toybox.WatchUi.View instance and optionally a Toybox.WatchUi.InputDelegate instance. The latter is not necessary for a watch face since input is not available to a watch face. For now, think of a view as a page to be shown.

function getInitialView() {
    // this is just a simple watch face.
    // so i just want to return the single view
    // in the array.
    return [ new helloView() ];
}

Since we used eclipse to create a new project, a sample view has already been created in the helloView.mc file. Because helloView.mc is sitting as a sibling to helloApp.mc, it has access to any of the classes declared inside. In this case, helloView is a class inside of helloView.mc. So, the above creates a new instance of that view and returns it as a single element array.

Like the App class, the View class also has methods to override. Three of the overridable methods were declared upon project creation: onLayout(), onShow(), and onUpdate(). onLayout() is called immediately after an app has started and allows you to load resources such as images. When the view is actually shown on the screen, onShow() is called. Use it to restore any state that might have been persisted. The last method is onUpdate(). This method is used to update dynamic content (such as the time for a watchface) and is called once a minute for watch faces and once a second for data fields. Keep in mind that Connect IQ tries to maintain a minimal footprint for user's watches; having hours, minutes, and seconds update on the watchface would consume more resources than hours and minutes alone.

using Toybox.WatchUi as Ui;
using Toybox.Graphics as Gfx;
using Toybox.System as Sys;
using Toybox.Lang as Lang;

class helloView extends Ui.View {

    // Update the view
    function onUpdate(dc) {
        // Set background color
        dc.clear();
        dc.setColor(Gfx.COLOR_WHITE, Gfx.COLOR_TRANSPARENT);
        dc.fillRectangle(0, 0, dc.getWidth(), dc.getHeight());

        // Get the current time
        var clockTime = Sys.getClockTime();
        var timeString = Lang.format("$1$:$2$", [clockTime.hour, clockTime.min]);

        // Draw the time
        dc.setColor(Gfx.COLOR_BLUE, Gfx.COLOR_WHITE);
        var x = dc.getWidth() / 2;
        var y = dc.getHeight() / 2;
        dc.drawText(x, y, Gfx.FONT_LARGE, timeString, Gfx.TEXT_JUSTIFY_CENTER);
    }

}

The onUpdate() method takes in a Toybox.Graphics.Dc instance (Dc == Device Context) which is used to update the screen.

The first three lines clear the screen using the current background color, set the foreground color white and the background color transparent, then create a rectangle starting at the (x,y) coordinates (0,0) and going to the width and height of the screen using the colors set in the previous call. Note the coordinates (0,0) start at the top left of the screen and increase as you go to the bottom right.

The following two lines get the current system time and create a string of hour:minute using Lang.format()'s string formatting.

The last four lines change the color to a blue foreground with a white background, find the center (x,y) coordinates and the draw the string on the screen.

Let's spice up the existing code by telling the user what those numbers on their watch mean. To do that, I'm just going to insert a new string just above the time.

// Update the view
function onUpdate(dc) {
    // ...

    // Draw the time
    dc.setColor(Gfx.COLOR_BLUE, Gfx.COLOR_WHITE);
    var x = dc.getWidth() / 2;
    var y = dc.getHeight() / 2;
    dc.drawText(x, y, Gfx.FONT_LARGE, timeString, Gfx.TEXT_JUSTIFY_CENTER);
    // I played around with some of the numbers for FONT_SMALL and dividing
    // the screen height by 3 for the square watch gave the result I was
    // looking for. Just play around with it.
    y = dc.getHeight() / 3;
    dc.drawText(x, y, Gfx.FONT_SMALL, "The time is", Gfx.TEXT_JUSTIFY_CENTER);
}

And that is it. Play around with positions, colors, or maybe even try to figure out how to pad the minutes with a zero when the minute is less than 10. One problem I ran into was that I expected hitting the run button to automatically save my current file and then compile, however, you need to manually save before running.


Comments