Thursday, 21 May 2015

Xamarin.Forms Tiled UI - Part 2

In my previous post I wrote about the SmartThings SmartApp I will be connecting my app to. In this post I will start with creating the app solution and then creating the page to host the UI.

Using Visual Studio 2013 I created a Xamarin.Forms solution by creating a new project and selecting the Blank App (Xamarin.Forms Portable) project template. I named the solution SmartTiles.

The template creates an iOS, Android and Windows Phone 8.0 project. It's always worth compiling the solution and even running it as soon as it's been created, to ensure that it has been set up correctly with all it's dependencies.

I'll be using the MVVM pattern so I created a Views and ViewModels folder in the root of the SmartTiles (Portable) PCL project

The app will initially consist of a single page for showing the tiles so I added a new item to Views folder and selected the Forms Xaml Page template naming the page MainPage. I then added the view-model by adding a Class called MainViewModel to the ViewModels folder.

The XAML created by the template for MainPage looks like this:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="SmartTiles.Views.MainPage">
    <Label Text="{Binding MainText}" VerticalOptions="Center" HorizontalOptions="Center" />
</ContentPage>


As you can see it contain a Label which binds it's Text property to a property called MainText. So to prove everything is working I'll add a property called MainText to MainViewModel:

public class MainViewModel
{
    public string MainText { get; private set; }

    public MainViewModel()
    {
        MainText = "Hello SmartTiles!";
    }
}


To bind my view-model to my view I need to set the BindingContext of the view which I will do in the view`s constructor:

public MainPage()
{
    InitializeComponent();
    this.BindingContext = new MainViewModel();
}


Now I just need to change the App class to load and show MainView by commenting out the code added by the template and setting the MainPage property to a new instance of the MainPage view:

public App()
{
    // The root page of your application
    MainPage = new MainPage();
    //MainPage = new ContentPage
    //{
    //    Content = new StackLayout
    //    {
    //        VerticalOptions = LayoutOptions.Center,
    //        Children = {
    //            new Label {
    //                XAlign = TextAlignment.Center,
    //                Text = "Welcome to Xamarin Forms!"
    //            }
    //        }
    //    }
    //};
}


The app is now ready to be run! Here it is running on the Windows Phone emulator:

Conclusion

Displaying a single Label in the middle of a page doesn't seem like a very big achievement! But we do now have three apps for iOS, Android and Windows Phone all running the same code and using the MVVM pattern.

In the next post we will actually start looking at the SmartTiles layout - promise!

Sunday, 17 May 2015

Xamarin.Forms Tiled UI - Part 1

Hello! Welcome to my blog on using Xamarin's tools to develop mobile apps.

I'm going to start with a project that provides a UI to my SmartThings devices. SmartThings sells a local hub device that is connected to your router providing connectivity between your Z-Wave or Zigbee devices and the SmartThings cloud. The devices are things like sensors for doors being opened, temperature, moisture, and also actuators which do things like switches and alarms.

The SmartThings cloud provides an online IDE in which you can write your own SmartApps. They are written in a language called Groovy which provides a Domain Specific Language for handling your devices events and invoking their actions.

So my first Xamarin post doesn't have any C#, it's Groovy!

But please don't be put off by this! This series of posts will show how to create a tiled interface (like the Windows 8 Start Menu) with each tile data bound to a device. I will be using the SmartApp as a source for the data to show in the tiles, and operations to call when interacting with the tiles. However you can easily use other web services to provide a UI to interact with them.

SmartApp

So let's start with the Groovy SmartApp. I have followed the tutorial here to create a SmartApp called REST Endpoints which responds to REST requests for sensor data and to perform actions.

The SmartApp script can be found in my SmartThings repository https://github.com/JasonBSteele/SmartThings where the README explains how to install it, get authorisation, and to call its endpoints.

I won't go through the SmartApp in detail but hopefully just enough for you to see how it wires up my devices to a REST interface. The snippet below handles the REST requests for switch devices. The path specifies the pattern to match against the URL and the action maps the HTTP verb to the function to call.

path("/switches") {
    action: [
        GET: "listSwitches"
    ]
}
path("/switches/:id") {
    action: [
        GET: "showSwitch"
    ]
}
path("/switches/:id/:command") {
    action: [
        GET: "updateSwitch"
    ]
}

Both listSwitches and showSwitch call deviceToJson with the attribute name of the value of a switch, which is switch. A JSON response is built in deviceMap which is of type Map (similar to a C# Dictionary). You will notice below that the return keyword is optional.

private deviceToJson(device, attributeName) {
    if (!device) 
        null

    def s = device.currentState(attributeName)
    def deviceMap = [id: device.id, name: device.displayName, unitTime: s?.date?.time]
    deviceMap[attributeName] = s?.value
    deviceMap
}

The JSON response for a single switch looks like this:

{
    "id":"be7c0195-ef58-4b16-969b-91299c1e0c82",
    "name":"My Switch",
    "unitTime":1425247415223,
    "switch":"on"
}

The remaining function updateSwitch calls updateToggle which finds the specific device in the switches collection and executes it's on or off command.

private void updateToggle(devices) {
    log.debug "updateToggle request: params: ${params}, devices: $devices.id"

    def command = params.command
    if (command) 
    {
        def device = devices.find { it.id == params.id }
        if (!device) {
            httpError(404, "Device not found")
        } 
        else {
            if(command == "toggle") {
                if(device.currentValue('switch') == "on")
                  device.off();
                else
                  device.on();
            }
            else {
                //else 'on' or 'off'
                device."$command"()
            }
        }
    }
}

You may have noticed that the HTTP verb GET invokes updateSwitch. For proper REST I should really use a PUT to change state but I have client applicatons for which it was easier to use a GET so decided, for now, to relax this convention.

Conclusion

We now have a web service for our Xamarin client to connect to. The next post will start with creating the app and it's main page.