Damian Mehers' Blog Android, VR and Wearables from Geneva, Switzerland.

30Nov/162

“Alexa, enable the My Notebook skill”

I just released my first Amazon Echo Skill, called "My Notebook".

You can use it to create notes in Evernote or OneNote using your Amazon Echo:

2016-11-30-18-37-54

To try it out, say "Alexa, enable the My Notebook skill".

It was rejected twice (for good reasons) during the review process, and I learned a lot as a result, especially around keeping the conversation going, responding to help requests etc.

For the technical, as well as using the Alexa Skills Kit, I used the Amazon API Gateway, an AWS Lambda (written in Python, since C# isn't yet available), and Amazon DynamoDB.

I'm caught between hoping it takes off, and people use it, but also hoping it isn't too popular, since it is free and I'm not keen on maxing out my credit card!

Filed under: Uncategorized 2 Comments
27Sep/160

Using Styles and Data Triggers to disable Xamarin forms while waiting

It's a common scenario: You are sending data to a service, or waiting for something to happen, and you don't want the user to interact with your form while that is happening.

untitled-1

The naive approach is to bind the IsEnabled property on your containing Layout to a boolean property in your View Model, but you'll soon find that IsEnabled is not inherited. Setting it on a StackLayout doesn't set it on all the controls embedded within that layout.

Here is a solution which binds the IsRunning property of an ActivityIndicator to a View Model property, and then uses a Style and a DataTrigger to react to the ActivityIndicator's running by setting the IsEnabled properties on the Layouts contained controls:

First I overlay an ActivityIndicator over my form using an AbsoluteLayout:

  <AbsoluteLayout>
    <ActivityIndicator
        IsRunning="{Binding Loading}" HorizontalOptions="Center" VerticalOptions="Center"
        IsVisible="{Binding Loading}" AbsoluteLayout.LayoutBounds="0,0,1,1"
        AbsoluteLayout.LayoutFlags="All" x:Name="ActivityIndicator" />
    <StackLayout Orientation="Vertical"
                 AbsoluteLayout.LayoutBounds="0,0,1,1" AbsoluteLayout.LayoutFlags="All">

Next in my StackLayout I define an explicit Style with a DataTrigger which disables the targeted control and sets its Opacity to 30% when the ActivityIndicator is running:

      <StackLayout.Resources>
        <ResourceDictionary>
          <Style TargetType="View" x:Key="MyBase">
            <!-- Disable controls when the activity indicator is running -->
            <Style.Triggers>
              <DataTrigger
                  TargetType="View"
                  Binding="{Binding Source={x:Reference ActivityIndicator}, Path=IsRunning}"
                  Value="True">
                <Setter Property="Opacity" Value="0.3" />
                <Setter Property="IsEnabled" Value="False" />
              </DataTrigger>
            </Style.Triggers>
          </Style>

You might hope that using an implicit style instead of an explicit style above would affect all views contained within the StackLayout, but it doesn't work like that. There is also the tantalizing and undocumented ApplyToDerivedTypes Style property, but that has no impact that I am aware of.

So instead I create implicit styles for each specific type of control I use inside my StackPanel:

          <!-- Define implicit styles for each control we use. -->
          <Style TargetType="Label" BasedOn="{StaticResource MyBase}" />
          <Style TargetType="Entry" BasedOn="{StaticResource MyBase}" />
          <Style TargetType="Button" BasedOn="{StaticResource MyBase}" />
        </ResourceDictionary>
      </StackLayout.Resources>

At least I'm able to reuse my base style. So here is my final complete view (but I'm not quite done yet):

<?xml version="1.0" encoding="utf-8"?>

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:shared="clr-namespace:LoadingDemo.Shared;assembly=LoadingDemo.Shared"
             BindingContext="{x:Static shared:Locator.MyViewModel}"
             x:Class="LoadingDemo.MainPage">

  <!-- Use an absolute layout to overlay one control over another -->
  <AbsoluteLayout>
    <ActivityIndicator
        IsRunning="{Binding Loading}" HorizontalOptions="Center" VerticalOptions="Center"
        IsVisible="{Binding Loading}" AbsoluteLayout.LayoutBounds="0,0,1,1"
        AbsoluteLayout.LayoutFlags="All" x:Name="ActivityIndicator" />

    <StackLayout Orientation="Vertical"
                 AbsoluteLayout.LayoutBounds="0,0,1,1" AbsoluteLayout.LayoutFlags="All">

      <StackLayout.Resources>
        <ResourceDictionary>
          <Style TargetType="View" x:Key="MyBase">
            <!-- Disable controls when the activity indicator is running -->
            <Style.Triggers>
              <DataTrigger
                  TargetType="View"
                  Binding="{Binding Source={x:Reference ActivityIndicator}, Path=IsRunning}"
                  Value="True">
                <Setter Property="Opacity" Value="0.3" />
                <Setter Property="IsEnabled" Value="False" />
              </DataTrigger>
            </Style.Triggers>
          </Style>

          <!-- Define implicit styles for each control we use. -->
          <Style TargetType="Label" BasedOn="{StaticResource MyBase}" />
          <Style TargetType="Entry" BasedOn="{StaticResource MyBase}" />
          <Style TargetType="Button" BasedOn="{StaticResource MyBase}" />
        </ResourceDictionary>
      </StackLayout.Resources>

      <Label Text="My Label" HorizontalOptions="Center" />
      <Entry Placeholder="Enter text here" />
      <Entry Placeholder="Enter text here" />
      <Entry Placeholder="Enter text here" />
      <Button Text="Click Me" Command="{Binding StartCommand}" HorizontalOptions="Center" />
    </StackLayout>
  </AbsoluteLayout>
</ContentPage>

This is my View Model:

  public class ViewModel : INotifyPropertyChanged {
    private bool _loading;

    public ViewModel() {
      StartCommand = new Command(Start);
    }

    private async void Start() {
      Loading = true;
      await Task.Delay(TimeSpan.FromSeconds(5));
      Loading = false;
    }

    public bool Loading {
      get {
        return _loading;
      }
      private set {
        _loading = value;
        OnPropertyChanged();
      }
    }

    public ICommand StartCommand { get; }

    public event PropertyChangedEventHandler PropertyChanged;
    private void OnPropertyChanged([CallerMemberName] string propertyName = null) {
      PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
  }

When I test the above code in an app I created, everything works swimmingly except for the Button. It doesn't become disabled when I click it.

The reason is that I am using the Command property to execute code in my View Model, and the ICommand interface to which it is bound has its very own CanExecute mechanism to decide when the Button can be clicked.

The solution is in the View Model, and involves raising the CanExecuteChanged event:

    public ViewModel() {
      // When you click the button run the Start method.  The command is available
      // when not loading
      StartCommand = new Command(Start, canExecute: () => !Loading);
    }
...
public bool Loading {
      get { ... }
      private set {
        _loading = value;
        OnPropertyChanged();
        StartCommand.ChangeCanExecute();
      }
    }

Here is the final View Model:

  public class ViewModel : INotifyPropertyChanged {
    private bool _loading;

    public ViewModel() {
      // When you click the button run the Start method.  The command is available
      // when not loading
      StartCommand = new Command(Start, () => !Loading);
    }

    private async void Start() {
      Loading = true;
      await Task.Delay(TimeSpan.FromSeconds(5));
      Loading = false;
    }

    public bool Loading {
      get {
        Debug.WriteLine($"Returning {_loading}");
        return _loading;
      }
      private set {
        _loading = value;
        OnPropertyChanged();
        StartCommand.ChangeCanExecute();
      }
    }

    public Command StartCommand { get; }

    public event PropertyChangedEventHandler PropertyChanged;
    private void OnPropertyChanged([CallerMemberName] string propertyName = null) {
      PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
  }

I like to put my View Models in a separate class library, which has no dependencies on Xamarin Forms, but the Command class comes from Xamarin Forms. Fortunately Xamarin Forms is now open source, so I can "borrow" the Command class' source and embed it within my class library and thus remove the Xamarin Forms dependency.

The complete solution is here in GitHub.

4Sep/160

UWP OAuth in Xamarin Forms using Xamarin.Auth

tl;dr: Complete standalone example here.

I recently wanted to authenticate to Evernote via OAuth in a Xamarin Forms app I'm creating.

There is an excellent Xamarin plugin, called Xamarin.Auth which lets you do the OAuth dance for iOS and Android Xamarin Forms apps, but even in the latest branch, I couldn't get it working on the Universal Windows Platform (UWP) app.

Comments pointed to using a the WebAuthenticationBroker from Microsoft. There are plenty of examples here, unfortunately none for Evernote.

I created and published an Evernote UWP OAuth example using WebAuthenticationBroker based on the Twitter example, which was similar, but not similar enough to be able to just copy/paste.

Once I had this working I was back to Xamarin Forms,and put together a complete standalone example using Google, to log you in to Google and then display your email address and photo. Here it is running in UWP:

uwp 04

I published that example on GitHub.

In order to make Xamarin.Auth work, you create a platform specific page renderer which does the OAuth. I'd already done this for iOS and Android. For Windows I implemented it like this:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Threading.Tasks;
using Windows.Security.Authentication.Web;
using Windows.Web.Http;
using Newtonsoft.Json;
using Xamarin.Auth;
using Xamarin.Forms.Platform.UWP;
using XamFormsUWPOAuth;
using XamFormsUWPOAuth.Shared;
using XamFormsUWPOAuth.UWP;

[assembly: ExportRenderer(typeof(AuthenticationPage), typeof(AuthenticationPageRenderer))]

namespace XamFormsUWPOAuth.UWP {
  class AuthenticationPageRenderer : PageRenderer {
    private bool _isShown;

    protected override async void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e) {
      base.OnElementPropertyChanged(sender, e);
      if (_isShown) return;
      _isShown = true;

      var code = await AuthenticateUsingWebAuthenticationBroker();
      var account = await ConvertCodeToAccount(code);
      await AuthenticationHelper.FetchGoogleEmailAndPicture(account);
    }


    private async Task<string> AuthenticateUsingWebAuthenticationBroker() {
      var googleUrl = Constants.AuthorizeUrl + "?client_id=" +
                      Uri.EscapeDataString(Constants.GoogleClientId);
      googleUrl += "&redirect_uri=" + Uri.EscapeDataString(Constants.GoogleCallbackUrl);
      googleUrl += "&response_type=code";
      googleUrl += "&scope=" + Uri.EscapeDataString(Constants.Scope);

      var startUri = new Uri(googleUrl);

      var webAuthenticationResult =
        await
          WebAuthenticationBroker.AuthenticateAsync(WebAuthenticationOptions.None, startUri,
            new Uri(Constants.GoogleCallbackUrl));
      return webAuthenticationResult.ResponseStatus != WebAuthenticationStatus.Success ? null : webAuthenticationResult.ResponseData.Substring(webAuthenticationResult.ResponseData.IndexOf('=') + 1);
    }


    private static async Task<Account> ConvertCodeToAccount(string code) {
      var httpClient = new HttpClient();
      IHttpContent content = new HttpFormUrlEncodedContent(new Dictionary<string, string> {
        {"code", code},
        {"client_id", Constants.GoogleClientId},
        {"client_secret", Constants.GoogleClientSecret},
        {"redirect_uri", Constants.GoogleCallbackUrl},
        {"grant_type", "authorization_code"},
      });
      var accessTokenResponse = await httpClient.PostAsync(new Uri(Constants.AccessTokenUrl), content);
      var responseDict =
        JsonConvert.DeserializeObject<Dictionary<string, string>>(accessTokenResponse.Content.ToString());

      return new Account(null, responseDict);
    }
  }
}

You could use one of the other Microsoft OAuth examples, or your own, in order to do the OAuth.

The AccountStore stuff is a little different. I wanted to reuse the AccountStore goodness that comes with Xamarin.Auth, but I needed a UWP AccountStore implementation. I also needed to ensure my shared code, in my shared project, picked up my UWP AccountStore. I did this by creating a simple container class in the shared project:

using System;
using Xamarin.Auth;

namespace XamFormsUWPOAuth.Shared {
public static class AccountStoreFactory {
    public static Func<AccountStore> Create { get; set; } = () => AccountStore.Create();
  }
}

I use this in order to get at the shared AccountStore throughout my code, rather than using AccountStore.Create() which you'd normally do. In my UWP startup code, I overwrite the default AccountStore (which doesn't exist on UWP anyway) in my App.xaml.cs :

    protected override void OnLaunched(LaunchActivatedEventArgs e) {
      AccountStoreFactory.Create = () => new UWPAccountStore();
      Frame rootFrame = Window.Current.Content as Frame;
              ...

My UWP specific AccountStore implementation was based on this one in the portable-bait-and-switch branch)

It makes use of the Igor Kulman's DataProtectionExtension implementation here.

uwp 01

uwp 03

uwp 04

Check out the full standalone example that works with iOS, Android and of course UWP in my GitHub repository.

Filed under: Xamarin No Comments
6Jul/160

Xamarin Media Plugin error: Only one operation can be active at at time

I've been getting System.InvalidOperationException: Only one operation can be active at a time in a Xamarin app I've created which uses the Media Plugin, and finally figured out why I was getting it. I was being spectacularly stupid.

I was triggering the taking of a photo in a form's Appearing event handler

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:behaviors="clr-namespace:QuickNote.Behaviors;assembly=QuickNote"
             xmlns:viewModels="clr-namespace:QuickNote.Shared.ViewModels;assembly=QuickNote"
             BindingContext="{x:Static viewModels:Locator.ExecuteQuickNote}"
             x:Class="QuickNote.ExecuteQuickNotePage" >
  <ContentPage.Behaviors>
    <behaviors:EventToCommandBehavior EventName="Appearing" Command="{Binding LoadCommand}" />
  </ContentPage.Behaviors>
  <StackLayout Orientation="Vertical">
      ...

The relevant line is the binding to the LoadCommand in the view model, which looked like this:

      LoadCommand = new Command(async () => {
        var options = new StoreCameraMediaOptions();
        using(var file = await CrossMedia.Current.TakePhotoAsync(options))
        {
          if (file == null) {
            Debug.WriteLine("No photo");
            return;
          }
          Debug.WriteLine("Got a photo");
        }
      });

The behavior I was seeing was that when the form loaded, the camera started, I took a photo, tapped the Use Photo button and then the app crashed with System.InvalidOperationException: Only one operation can be active at a time.

Can you guess why? I finally realized that after taking the photo it was re-displaying the form, causing the appearing event to be fired again, and thus causing a new photo to be taken while the old one was being taken. Hence the crash. D'oh.

My clue was that I discovered that by inserting a await Task.Yield(); at the start of the LoadCommand delegate, it stopped the crash, but started the camera again after I'd finished taking a photo.

The solution was to add a flag which I checked to ensure I didn't run the command more than once:

      LoadCommand = new Command(async () => {
        if(_loaded) return;
        _loaded = true;
            ...

The error was perfectly correct, I was causing more than one "take photo" operation to be active at the same time, I just didn't realize why.

10Apr/162

Getting Xamarin Xaml Intellisense when the binding context is set in code

I'm working on an app where I navigate from one page to another, passing data by setting the new page's binding context:

Navigation.PushAsync(new QuickNotePage() { BindingContext = quickNote});

When designing the Xaml for QuickNotePage I was pained to see that Intellisense wasn't working, because I wasn't setting the bindingContext for the page in Xaml.

A quick search led me to this page which pre-dates the current version of Xamarin, but nevertheless reminded me of the old design-time namespaces that were auto-generated when I worked on WPF and Silverlight.

This is the Xaml I'm using now to get Intellisense auto-completion and the ability to navigate to properties:

Before:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="QuickNoteForms.QuickNotePage">
    <Label Text="{Binding Title}"/>
</ContentPage>

After:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="QuickNoteForms.QuickNotePage"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             mc:Ignorable="d"
             xmlns:quickNoteViewModels="clr-namespace:QuickNote.ViewModels;assembly=QuickNoteForms"
             d:DataContext="{d:DesignInstance quickNoteViewModels:QuickNoteViewModel}">
    <Label Text="{Binding Title}"/>
</ContentPage>

Where QuickNoteViewModel is the ViewModel class, and instance of which I set above when instantiating the page.

Filed under: Xamarin 2 Comments
8Apr/164

Visual Studio missing “Forms Xaml Page” from “Add|New Item” menu using Xamarin

Not sure why this is happening, but its been happening on all my installations of Xamarin with Visual Studio 2015.

All the tutorials and web pages talk about using Project|Add New Item and adding a new "Forms Xaml Page". But whenever I install Xamarin and Visual Studio 2015, I just get the "Forms ContentPage" and "Forms ContentView" which just generate a C# file, no Xaml.

To fix this, I copied XamlPage.zip from

C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\Extensions\Xamarin\Xamarin\4.0.3.214\T\IT\Cross-Platform\Code

to

C:\Users\your name here\Documents\Visual Studio 2015\Templates\ItemTemplates\Visual C#

Finally, it is there:
Screenshot 2016-04-08 11.10.19

Filed under: Xamarin 4 Comments
31Jan/163

Creating a Windows Universal app to talk Bluetooth LE, save to SQLite and expose a REST service

The Goal

I've had a couple of TI SensorTags sitting on my shelf for a couple of years. These are the original ones, which have been superseded by smaller ones that have additional sensors for light and sound.

Sensor Tag with no caseSensor Tag with case

They are wonderful devices. They last for over a year on a watch battery, they talk Bluetooth LE, and they have loads of sensors including Temperature (both spot temperature of a nearby object, and overall ambient temperature), Gyroscope, Accelerometer, Magnetometer, Barometer, Humidity, etc.

Last, but not least, they cost less than US$30. Unless you actually enjoy wiring physical sensors into an Arduino or Raspberry PI, I think Sensor Tags are a great way to start collecting all kinds of information.

Rather than have a phone sitting talking Bluetooth LE, I decided I wanted to use a Mac Mini server that I have running Windows, which I could run continuously to capture, store and serve the sensor information.

My goal was to:

  • Create a Windows Universal App that talks Bluetooth LE to the Sensor Tag
  • Save the captured information to an SQLite database
  • Serve the captured information using REST (/GetTemperatures?start=201501010000&end=201701010000)

At each step I hit roadblocks, and the purpose of this blog post is to try to capture what I did to overcome them, in the hope that other people may benefit from my pain.

Although I've been mainly writing Java/Android, C, TypeScript and JavaScript over the last three years, I still retain a soft spot for C# and the associated tooling of Visual Studio and Resharper.

I really appreciate the C# syntax and associated features such as lambdas, and LINQ.

I wanted to try my hand at create a Windows app, to see how much I'd lost over the last few years.

Bluetooth LE, SensorTag and Windows Universal

I started off creating a new Windows Universal app in Visual Studio. I browsed the documentation, and found the classes associated with using Bluetooth LE. I liked the fact that my app would be able to run on desktops down to phones.

My initial code:

      _watcher = new BluetoothLEAdvertisementWatcher();
      _watcher.Received += BluetoothReceived;
      _watcher.Stopped += BluetoothStopped;
      _watcher.Start();

When I ran this, I got the following exception: onecoreuap\drivers\wdm\bluetooth\user\winrt\common\devicehandle.cpp(100)\ Windows.Devices.Bluetooth.dll!51D26D1B: (caller: 51D273AE) Exception(1) tid(13c0) 80070005 Access is denied.

Turns out I needed to add Bluetooth to my app's capabilities by double-clicking the Package.appxmanifest file in the Solution Explorer, going to Capabilities and checking Bluetooth.

Enabling Bluetooth in Windows Universal App

Once that was done, I was able to look for the SensorTag's Service UUID, and then check for the correct characteristics and enable the reception of the sensor's data:

    const string BaseUuidStart = "f000";
    const string BaseUuidEnd = "-0451-4000-b000-000000000000";

    const string TempData = "aa01";
    const string TempConfig = "aa02";
    const string AccelData = "aa11";
    const string AccelConfig = "aa12";
    const string HumidData = "aa21";
    const string HumidConfig = "aa22";
    const string MagnetData = "aa31";
    const string MagnetConfig = "aa32";
    const string BaromData = "aa41";
    const string BaromConfig = "aa42";
    const string GyroData = "aa51";
    const string GyroConfig = "aa52";

    private bool _attaching;
    private readonly List<BluetoothLEDevice> _devices = new List<BluetoothLEDevice>();
    private readonly List<GattCharacteristic> _characteristics = new List<GattCharacteristic>();

    private async void BluetoothReceived(BluetoothLEAdvertisementWatcher sender,
      BluetoothLEAdvertisementReceivedEventArgs args) {
      if (_attaching) return;
      try {
        var device = await BluetoothLEDevice.FromBluetoothAddressAsync(args.BluetoothAddress);
        _devices.Add(device);
        _attaching = true;
        device.ConnectionStatusChanged += DeviceConnectionStatusChanged;
        device.GattServicesChanged += DeviceGattServicesChanged;
        foreach (var service in device.GattServices) {
          var serviceUuid = service.Uuid.ToString().ToLowerInvariant();
          if (!serviceUuid.StartsWith(BaseUuidStart) || !serviceUuid.EndsWith(BaseUuidEnd)) {
            continue;
          }
          foreach (var characteristic in service.GetAllCharacteristics()) {
            var characteristicUuid = characteristic.Uuid.ToString().ToLowerInvariant();
            if (_characteristics.Any(c => c.Uuid.ToString() == characteristicUuid)) {
              continue;
            }
            var characteristicType = characteristicUuid.Substring(BaseUuidStart.Length, 4);
            switch (characteristicType) {
              case AccelData:
              case BaromData:
              case HumidData:
              case GyroData:
              case MagnetData:
              case TempData: {
                _characteristics.Add(characteristic);
                characteristic.ValueChanged += CharacteristicChanged;
                var status =
                  await characteristic.WriteClientCharacteristicConfigurationDescriptorAsync(
                    GattClientCharacteristicConfigurationDescriptorValue.Notify);
                Debug.WriteLine("Subscribed .... with status " + status);
                break;
              }
              case AccelConfig:
              case BaromConfig:
              case HumidConfig:
              case GyroConfig:
              case MagnetConfig:
              case TempConfig: {
                var status = await characteristic.WriteValueAsync(new byte[] {1}.AsBuffer());
                break;
              }

              default:
                Debug.WriteLine("Ignoring characteristic: " + characteristicType);
                break;
            }
          }
        }
        sender.Stop();
      }
      catch (Exception ex) {
        Debug.WriteLine("got " + ex);
      }
    }

I used the Sensor Tag documentation to know about the GUIDs used for the services and characteristics.
I found I needed to press Advertise the button on the side of my Sensor Tag to get it to be seen.

Capturing the values was pretty easy, but I did hit one stumbling block which was the temperature. There is an algorithm described in the documentation as to how to transform the series of bytes received into the spot and ambient temperature in degrees Celsius. When I tried using it I got garbage values, but eventually found this C# example showing how they can be calculated:

    private async Task ProcessTempData(string bluetoothId, byte[] rawData) {
      // Extract ambiant temperature 
      var ambTemp = BitConverter.ToUInt16(rawData, 2)/128.0;

      // Extract object temperature 
      int twoByteValue = BitConverter.ToInt16(rawData, 0);
      var vobj2 = twoByteValue*0.00000015625;
      var tdie = ambTemp + 273.15;
      const double s0 = 5.593E-14; // Calibration factor 
      const double a1 = 1.75E-3;
      const double a2 = -1.678E-5;
      const double b0 = -2.94E-5;
      const double b1 = -5.7E-7;
      const double b2 = 4.63E-9;
      const double c2 = 13.4;
      const double tref = 298.15;
      var s = s0*(1 + a1*(tdie - tref) + a2*Math.Pow(tdie - tref, 2));
      var vos = b0 + b1*(tdie - tref) + b2*Math.Pow(tdie - tref, 2);
      var fObj = vobj2 - vos + c2*Math.Pow(vobj2 - vos, 2);
      var tObj = Math.Pow(Math.Pow(tdie, 4) + (fObj/s), .25);
      var objTemp = tObj - 273.15;

      await SaveTemperature(bluetoothId, ambTemp, objTemp);
    }

SQLite and Windows Universal

Installing SQLite for Windows was pretty easy, but I couldn't find clear, complete instructions. In short I used NuGet to install

  • SQLite.Net-PCL
  • SQLite.Net.Async-PCL
  • SQLite.Net.Core-PCL

Once I had this installed, I could define classes corresponding to the tables I wanted to create, such as:

  public class Temperature
  {
    public int Id { get; set; }
    public DateTime Timestamp { get; set; }
    public string BluetoothId { get; set; }
    public double Ambient { get; set; }
    public double Spot { get; set; }
  }

Then I could initialize the database:

    private SQLiteAsyncConnection _asyncConnection;
    private async Task InitializeDatabase() {
      Debug.WriteLine("Initializing database");
      var databasePath = Path.Combine(Windows.Storage.ApplicationData.Current.LocalFolder.Path, "sensortag.db");
      var connectionFactory = new Func<SQLiteConnectionWithLock>(() => new SQLiteConnectionWithLock(new SQLitePlatformWinRT(), new SQLiteConnectionString(databasePath, true)));
      _asyncConnection = new SQLiteAsyncConnection(connectionFactory);
      await _asyncConnection.CreateTablesAsync(typeof (Temperature));
      Debug.WriteLine("Initialized database");
    }

And then write the data:

    private async Task SaveTemperature(string bluetoothId, double ambTemp, double objTemp) {
      var temperature = new Temperature {
        Timestamp = DateTime.Now,
        BluetoothId = bluetoothId,
        Ambient = ambTemp,
        Spot = objTemp
      };
      Debug.WriteLine("Writing temperature");
      await _asyncConnection.InsertAsync(temperature);
      Debug.WriteLine("Wrote temperature");
    }

It turns out this was wrong, though it is what was shown in the Stack Overflow posts I found. The reason that it is wrong is that it is creating a new database connection each time the factory lambda is invoked. When I used this code all would run fine for a while, until eventually I hit an SQLite Busy exception:

Exception thrown: 'SQLite.Net.SQLiteException' in mscorlib.ni.dll
SQLite.Net.SQLiteException: Busy
   at SQLite.Net.PreparedSqlLiteInsertCommand.ExecuteNonQuery(Object[] source)
   at SQLite.Net.SQLiteConnection.Insert(Object obj, String extra, Type objType)
   at SQLite.Net.SQLiteConnection.Insert(Object obj)
   at SQLite.Net.Async.SQLiteAsyncConnection.<>c__DisplayClass14_0.<InsertAsync>b__0()
   at System.Threading.Tasks.Task`1.InnerInvoke()
   at System.Threading.Tasks.Task.Execute()

The simple solution was to create a single database connection instance, and serve that, rather than continually serving new ones:

    private SQLiteAsyncConnection _asyncConnection;
    private SQLiteConnectionWithLock _sqliteConnectionWithLock;
    private async Task InitializeDatabase() {
      Debug.WriteLine("Initializing database");
      var databasePath = Path.Combine(Windows.Storage.ApplicationData.Current.LocalFolder.Path, "sensortag.db");
      _sqliteConnectionWithLock = new SQLiteConnectionWithLock(new SQLitePlatformWinRT(), new SQLiteConnectionString(databasePath, true));
      var connectionFactory = new Func<SQLiteConnectionWithLock>(() => _sqliteConnectionWithLock);
      _asyncConnection = new SQLiteAsyncConnection(connectionFactory);
      await _asyncConnection.CreateTablesAsync(typeof (Temperature));
      Debug.WriteLine("Initialized database");
    }

Exposing a REST Service from Windows Universal

This was supposed to be trivially easy. I've done plenty of WCF in the past, and know how ridiculously straightforward it should be to expose a REST service from an app. Except that Windows Universal doesn't currently support WCF.

I went searching and found Restup, currently in Beta, which aims to expose REST endpoints for Windows Universal apps.

I used NuGet to install it. I had to check the Include prerelease option because it was currently in beta.

Setting up was pretty easy:

    private async Task InitializeWebServer() {
      await InitializeDatabase();
      var webserver = new RestWebServer(); //defaults to 8800
      webserver.RegisterController<SensorTagService>(_asyncConnection);

      await webserver.StartServerAsync();
    }
  [RestController(InstanceCreationType.Singleton)]
  class SensorTagService {
    private readonly SQLiteAsyncConnection _connection;

    public SensorTagService(SQLiteAsyncConnection sqLiteAsyncConnection) {
      _connection = sqLiteAsyncConnection;
    }

    [UriFormat("/GetTemperatures\\?start={start}&end={end}")]
    public async Task<GetResponse> GetTemperatures(string start, string end) {
      Debug.WriteLine("got temp request");
      ...
    }
  }

Note the escaping of the question mark in the UriFormat? I wanted to pass parameters to my endpoint, rather than use values that are part of the path, but all the RestUP examples showed values in the path. I eventually came up with this solution, however it may be unnecessary by the time you read this.

Once again the security model bit me, and I got the following exception:

An exception of type 'System.UnauthorizedAccessException' occurred in mscorlib.ni.dll but was not handled in user code
WinRT information: At least one of either InternetClientServer or PrivateNetworkClientServer capabilities is required to listen for or receive traffic
Additional information: Access is denied.

Once again I edited the app's capabilities by double-clicking the Package.appxmanifest file in the Solution Explorer, going to Capabilities and checking

  • Internet (Client),
  • Internet (Client & Server) and
  • Private Networks (Client & Server) (so that I could use my service on my home network).

Accessing a local Windows Universal app from your web browser

Try as I might, I was not able to use my local Chrome browser to access my service. I resorted to using a totally separate machine to invoke my service. I used the CheckNetIsolation tool. I ensure that the Allow Network Loopback option was set for my project Visual Studio. I turned off my firewalls. Nothing!

Conclusions

The Bluetooth side of things was quite easy, but exposing a REST API was far too hard, despite the sterling work of Tom Kuijsten and the Restup project. Not being able to access my service locally was a complete pain - the Windows Universal restrictions on being able to be accessed from the local host seem strange - almost as though they are trying to stop you from building traditional apps that talk to Windows Universal apps ...

In the end I'll likely use the Windows Universal app to capture the SensorTag data via Bluetooth LE, and then create a Node.JS app to serve it over REST, sharing the same SQLite database, with code to handle retrying if the database is busy when inserting new values.

I'll also push the data to a Node-RED instance to act on the data.

Filed under: Uncategorized 3 Comments
20Jan/161

Radical surgery: Slimming Pebble apps down to run on Aplite

A long way to go

In December 2015, when first I released Powernoter, an unofficial Evernote client for the Pebble Watch, I initially targeted Pebble Time (codename Basalt), and Pebble Time Round (codename Chalk).

After all there was already the official Evernote Pebble app (which I also created) for the original Pebble (codename Aplite).

Then Pebble released a firmware update and SDK for the original Pebble which meant that I could easily release Powernoter for the original Pebble too, using the same SDK I'd already used.

This is the build log from the first time I built Powernoter targeting Aplite (the original Pebble), Basalt (Pebble Time) and Chalk (Pebble Time Round):

-------------------------------------------------------
BASALT APP MEMORY USAGE
Total size of resources:        26461 bytes / 256KB
Total footprint in RAM:         25895 bytes / 64KB
Free RAM available (heap):      39641 bytes
------------------------------------------------------- 
...
-------------------------------------------------------
CHALK APP MEMORY USAGE
Total size of resources:        26461 bytes / 256KB
Total footprint in RAM:         25943 bytes / 64KB
Free RAM available (heap):      39593 bytes
------------------------------------------------------- 
...
-------------------------------------------------------
APLITE APP MEMORY USAGE
Total size of resources:        26341 bytes / 125KB
Total footprint in RAM:         23789 bytes / 24KB
Free RAM available (heap):      787 bytes
------------------------------------------------------- 

See the 787 bytes on the last line? That was how much free memory my app had before it even started running on an original Pebble. Before it created its first window or allocated memory to receive and send messages.

Although I successfully built Powernoter for Aplite, it couldn't even start up, crashing immediately as it ran out of memory.

Not so verbose with the error messages

The first thing I did, was to run the pebble analyze-size command, which gave me a sense of where the memory was being used.

Like all good programmers, I very carefully and very consistently checked all OS calls for out of memory situations, and logged (very) verbose messages if I ran out of memory. Like this:

  bitmap_layer = bitmap_layer_create(image_layer_size);
  if(!bitmap_layer) {
    APP_LOG(APP_LOG_LEVEL_ERROR, "Couldn't allocate memory for the image");
    ...

All those strings had to be allocated somewhere. I went through my app and removed all those lovely descriptive messages. Instead I just logged the line number - that was enough to work out where it went wrong.

  bitmap_layer = bitmap_layer_create(image_layer_size);
  if(!bitmap_layer) {
    OOMCF();
    ...

I defined a couple of macros for Out Of Memory (OOM) situations:

#define OOM(s) log_oom(__FILE_NAME__, __LINE__, (int)s)
#define OOMCF() log_create_failed(__FILE_NAME__, __LINE__)
void log_create_failed(char* file, int line) {
  app_log(APP_LOG_LEVEL_DEBUG, file, line, "create failed %d free", (int)heap_bytes_free());
}

void log_oom(char* file, int line, int size) {
  app_log(APP_LOG_LEVEL_DEBUG, file, line, "oom %d, %d", size, (int)heap_bytes_free());
}

I also declared some handy logging macros, so that debug log strings were stripped out of shipping builds

#ifdef SHIPPING
#define LOG_MEM_START()
#define LOG_MEM_END()
#define LOG_FUNC_START(name)
#define LOG_FUNC_END(name)
#define LOG_DBG(fmt, args...)
#define LOG_ERR(fmt, args...) app_log(APP_LOG_LEVEL_ERROR, __FILE_NAME__, __LINE__, " ")
#else
#define LOG_DBG(fmt, args...) app_log(APP_LOG_LEVEL_DEBUG, __FILE_NAME__, __LINE__, fmt, ## args)
#define LOG_MEM_START() app_log(APP_LOG_LEVEL_DEBUG, __FILE_NAME__, __LINE__, "start %d", (int)heap_bytes_free())
#define LOG_MEM_END() app_log(APP_LOG_LEVEL_DEBUG, __FILE_NAME__, __LINE__, "end %d", (int)heap_bytes_free())
#define LOG_FUNC_START(name) app_log(APP_LOG_LEVEL_DEBUG, __FILE_NAME__, __LINE__, "%s invoked", name)
#define LOG_FUNC_END(name) app_log(APP_LOG_LEVEL_DEBUG, __FILE_NAME__, __LINE__, "%s returning", name)
#define LOG_ERR(fmt, args...) app_log(APP_LOG_LEVEL_ERROR, __FILE_NAME__, __LINE__, fmt, ## args)
#endif

Use statics in moderation

Next I looked into how I was defining static variables. I like statics because they are only visible to the file in which they are declared: a primitive form of encapsulation. A typical C source file might have started with:

static CustomMenu* customMenu;
static CustomMenuItem* items;
static uint16_t itemCount;
static AppTimer *send_timeout_timer;
static NoteSelectedCallback noteSelectedCallback;

The types don't matter (CustomMenu is my own class that does things like automatically scrolling long menu items).

What matters is that I have four pointers and a short declared as statics, meaning I have a whole chunk of memory statically allocated just for this one file.

Powernoter is not a small app ... this multiplied by tens of files means that I had a load of memory statically allocated, which was never used unless the user was actually invoking the functionality represented by those files.

The solution was to move to a dynamically allocated memory:

typedef struct NoteList {
  CustomMenu *customMenu;
  CustomMenuItem *items;
  uint16_t itemCount;
  AppTimer *send_timeout_timer;
  NoteSelectedCallback noteSelectedCallback;
} NoteList;

I only allocate a NoteList when it is being used, and free it as soon as possible.

Omit needless code

Although the SDK includes definitions for things like DictationSession on Aplite, so that code can be compiled regardless of the platform (you do need to check return calls though), it made no sense to include that code at all. I #ifdefed whole chunks of code to reduce the app size:

#ifdef SUPPORTS_VOICE
static void dictation_session_callback(DictationSession *session, DictationSessionStatus status,
                                       char *transcription, void *context) {
  LOG_FUNC_START("dictation_session_callback");
  if(DictationSessionStatusSuccess == status) {
    if(!noteContext->waitingAnimation) {
      if(noteContext->customMenu) {
        layer_set_hidden(custom_menu_get_layer(noteContext->customMenu), true);
      }
...
}
#endif

SUPPORTS_VOICE is my own macro:

#ifndef PBL_PLATFORM_APLITE
#define SUPPORTS_VOICE
#else
#define LOW_MEMORY_DEVICE
#endif

Pebble have added a PBL_MICROPHONE macro so my use of SUPPORTS_VOICE is no longer necessary.

I did the same thing for animations and color support.

Although I think I am a decent enough software engineer, I am under few illusions as to my abilities as a designer, which is why I let you choose your very own foreground and background colors in Powernoter, except if you are running on an original Pebble, in which case all that code, including the color names, is #ifdefed out.

Be careful what you ask for (when calling app_message_xyz_maximum)

Once upon a time were were limited to 120 or so bytes per message sent between the watch and the phone. I wrote inordinately complex code to page menu items in dynamically from the phone to the watch so that you could scroll through infinitely long menus. Then Pebble gave us what we wanted, with massive (8Kish) message buffers.

When you only have a little memory free to start with, the last thing you want to do is go allocating 8K buffers. It won't work.

My code to determine the size of the input buffer looks like this now:

#ifdef LOW_MEMORY_DEVICE
#define MAX_INBOX_SIZE 512
#else
#define MAX_INBOX_SIZE 4096
#endif

The LOW_MEMORY_DEVICE macro is set on Aplite only. Users on the original Pebble won't see an enormous number of notes listed, or a lot of a note's content, but at least they'll see something.

Make long strings into Resources

There is an excellent Internationalization sample for the Pebble. Although Powernoter isn't internationalized, there are no strings hardcoded in code ... all strings are accessed via a single point. I include the strings in a single source file in the app, except for certain very long strings, such as the About page. These I load as resources from files:

static char* loadResource(uint32_t resourceId) {
  ResHandle handle = resource_get_handle(resourceId);
  size_t res_size = resource_size(handle);

  // Copy to buffer
  char* result = (char*)malloc(res_size + 1);
  if(!result) {
    OOM(res_size);
    result = (char*)malloc(1);
    if(result) {
      *result = '\0';
    }
    return result;
  }
  resource_load(handle, (uint8_t*)result, res_size);
  result[res_size] = '\0';
  return result;
}

Once I'm done with them, I free them as quickly as possible.

Summary

In case you were wondering, this is how things look right now:

CHALK APP MEMORY USAGE
Total size of resources:        27313 bytes / 256KB
Total footprint in RAM:         24244 bytes / 64KB
Free RAM available (heap):      41292 bytes
-------------------------------------------------------
BASALT APP MEMORY USAGE
Total size of resources:        27313 bytes / 256KB
Total footprint in RAM:         24176 bytes / 64KB
Free RAM available (heap):      41360 bytes
-------------------------------------------------------
APLITE APP MEMORY USAGE
Total size of resources:        13966 bytes / 125KB
Total footprint in RAM:         17353 bytes / 24KB
Free RAM available (heap):      7223 bytes
------------------------------------------------------- 

Getting from 787 bytes free to 7,223 bytes free, so that Powernoter can really run on Aplite involved many changes, some which I'd say were generally good practice (reducing statics and instead using structs which are allocated/freed), and some less so (removing error log messages).

In general I don't think the code looks too unreadable as a result of supporting Aplite ... certainly I'd prefer not to have as many #ifdefs sprinkled throughout my code as I have, but it's not that bad.

You may also wish to check out this Pebble presentation on Pebble app memory usage.

One thing is for sure, the changes I had to make to Powernoter to get it to run on Aplite are nothing compared with the miracles the Pebble team pulled to get the original Pebble to support the same SDK as Pebble Time and Pebble Time Round.

About me

I'm an independent consultant and speaker, available for ad-hoc Pebble, Android and Android Wear and Tizen consulting and development.

If you like and use Powernoter, please consider supporting it.

On the other hand if something is missing or doesn't work, check out this Trello board where you can comment to request enhancements or report bugs.

Filed under: Pebble, Wearables 1 Comment
13Nov/150

Making using TypeScript for Google Apps Scripts more convenient on OS X

I've started to use TypeScript in IntelliJ, and wanted to use it for a Google Apps Script App that I'm writing.

There are a couple of issues with using TypeScript for this: The first is that Google Apps Script doesn't directly support TypeScript, and the second is that the Apps Scripts editor is web based.

The first issue isn't really an issue, since the TypeScript is transpiled directly into JavaScript. But the second one is an issue. It would be painful to have to open the generated JavaScript in IntelliJ, copy it into the clipboard, activate the web-based editor, select the old content, paste the new content from the clipboard, and save it, every time I make a change to the TypeScript.

Fortunately I've found a simple way to automate all of this using AppleScript.

Firstly, I ensure that the Apps Script editor is open in its own window. My project is called "Documote" and this is what the Google Chrome window looks like:
documote chrome window

Secondly I've created this AppleScript file to copy the generated JavaScript to that project:

try
    set project_name to "Documote"
    set file_name to "/Users/damian/.../documote/Code.js"
    set the_text to (do shell script "cat " & file_name)
    set the clipboard to the_text
    tell application "Google Chrome"
        set visible of window project_name to false
        set visible of window project_name to true
        activate window project_name
        tell application "System Events" to keystroke "a" using command down
        paste selection tab project_name of window project_name
        tell application "System Events" to keystroke "s" using command down
    end tell
on error errMsg
    display dialog "Error: " & errMsg
end try

You'd need to change the first couple of lines to reflect your situation. The reason for hiding and showing the window is to activate the window.

Once you have the AppleScript you can assign it a shortcut.

Filed under: Uncategorized No Comments
11Nov/151

Building an Amazon Echo Skill to create Evernote notes

First, a demo: Alexa, tell Evernote to create a note "Remember to call my Mother":

I recently acquired an Amazon Echo, and although there is limited support for interacting with Evernote via IFTTT, I wanted to simply create Evernote notes as in the demo above.

I’m going to share how I created an Amazon Echo Skill to accomplish what it shown in the video above, and what roadblocks I hit on the way.

Updating the example

I started with the sample Amazon Echo skill which uses lambdas, and got that working pretty quickly.

To update it to work with Evernote, I changed the JavaScript code that recognized the intent to invoke saveNote when the intent is TakeANote (you'll see where this intent is set up later):

**
 * Called when the user specifies an intent for this skill.
 */
function onIntent(intentRequest, session, callback) {
    console.log("onIntent requestId=" + intentRequest.requestId +
        ', sessionId=' + session.sessionId);
    var intent = intentRequest.intent, intentName = intentRequest.intent.name;
    // Dispatch to your skill's intent handlers
    if ("TakeANote" === intentName) {
        saveNote(intent, session, callback);
    }
    else {
        throw "Invalid intent: " + intentName;
    }
}

Creating the note

My code to create the Evernote note (invoked by saveNote above) is pretty much boilerplate. It pulls the content from the list of slots (defined below) and uses it to create a note using the Evernote API:

function saveNote(intent, session, callback) {
    var cardTitle = intent.name;
    var contentSlot = intent.slots["Content"];
    var repromptText = "";
    var sessionAttributes = [];
    var shouldEndSession = false;
    var speechOutput = "";
    if (contentSlot) {
        var noteText = contentSlot.value;
        sessionAttributes = [];
        speechOutput = "OK.";
        repromptText = "What was that?";
        shouldEndSession = true;
        var noteStoreURL = '...';
        var authenticationToken = '...';
        var noteStoreTransport = new Evernote.Thrift.NodeBinaryHttpTransport(noteStoreURL);
        var noteStoreProtocol = new Evernote.Thrift.BinaryProtocol(noteStoreTransport);
        var noteStore = new Evernote.NoteStoreClient(noteStoreProtocol);
        var note = new Evernote.Note();
        note.title = "New note from Alexa";
        var nBody = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
        nBody += "<!DOCTYPE en-note SYSTEM \"http://xml.evernote.com/pub/enml2.dtd\">";
        nBody += "<en-note>" + noteText + "</en-note>";
        note.content = nBody;
        noteStore.createNote(authenticationToken, note, function (result) {
            console.log('Create note result: ' + JSON.stringify(result));
            callback(sessionAttributes, buildSpeechletResponse(cardTitle, speechOutput, repromptText, shouldEndSession));
        });
    }
    else {
        speechOutput = "I didn't catch that note, please try again";
        repromptText = "I didn't hear that note.  You can take a note by saying Take a Note followed by your content";
        callback(sessionAttributes, buildSpeechletResponse(cardTitle, speechOutput, repromptText, shouldEndSession));
    }
}

Notice the hard-coded authenticationToken? That means this will only work with my account. To work with anyone's account, including yours, we'd obviously need to do something different. More on that in a moment.

Packaging it up

I zipped up my JavaScript file, together with my node_modules folder and a node package.json:

{
  "name": "AlexaPowerNoter",
  "version": "0.0.0",
  "private": true,
  "dependencies": {
    "evernote": "~1.25.82"
  }
}

Once done, I uploaded my zip to my Amazon Skill, and then published it.

The Skill information

This is the skill information I used:
Alexa Skill Information
Obviously I couldn't use trademarked term "Evernote" as the Invocation Name in something that was public, but just for testing for myself, I think I'm OK.

The Interaction Model

I defined the interaction model like this:
Alexa Interaction Model
The sample utterances is way too limited here - Amazon recommend having several hundred utterances for situations where you allow free-form text. It would also be cool to be able to have an intent to let you search Evernote.

Once I'd done this, and set up my Echo to use my development account, I could create notes.

Authentication roadblock

The next step was to link anyone's Evernote account into the Skill. This is where I hit the roadblock. Amazon require that the authentication support OAUTH 2.0 implicit grant and Evernote supports OAUTH 1. I could attempt to create a bridging service, but the security implications of doing so are scary, and doing it properly would require more time than I have right now.

The source is in GitHub

I've published the source to this app in my GitHub account here. If you are a developer and want to try it out, get an Evernote Developer auth token and plug in the URL and token in the noteStoreURL and authenticationToken above.

Filed under: Uncategorized 1 Comment