Pushing pins to Pebble Time timeline from .NET code

Timeline on Pebble Time Pebble Time timeline is a very cool user interface allowing you to see future and past events and act upon them right on your watch. Right out of the box Pebble Time supports calendar pins that shows your future and past appointments in the timeline as well as weather alerts. But the real power comes from 3rd party apps using timeline – they can add anything from sports scores to latest news to TV showtimes – limit is just your imagination.
Pebble has always had open SDK – this is one of its major strengths, and Timeline is not an exception. Timeline API is a very straightforward way to push your own pins to users of your app. There’re various examples and libraries including PHP and node.js on how to deal with the timeline, but I, being mostly a Microsoft developer by trade, decided to bring Timeline into .NET. This particular example is in ASP.NET – pin is pushed from Webpage when user clicks a button, but it’s just one of the possible scenarios.

In order to push timeline pins successfully you will need 2 pieces:

  1. A watchapp that runs on Pebble. In fact after first run, that subscribes user to timeline, the app doesn’t have to be running on the watch anymore. It doesn’t even have to be on the watch. As long as it simple remains in your locker on the phone – you will continue to receive its pins
  2. Your own server that sends calls to Pebble public Timeline API to control pins

For the item 1 – you need to create a very basic watch app in Pebble standard C SDK (if you’re using CloudPebble – select “Minimal” from templates). You will not be writing a single line of C code, instead Pebble Timeline is controlled from PebbleKitJS. Add a JavaScript source to your project and add following code to it:

Pebble.addEventListener("ready",
   function(e) {
      Pebble.timelineSubscribe('TestTopic', 
         function () { 
            console.log('Subscribed to TestTopic');
         }, 
         function (errorString) { 
            console.log('Error subscribing to topic: ' + errorString);
         }
     );
   }
);

What this does is: when Pebble JS is ready – subscribes user of your app to timeline topic “TestTopic”. Note that this is just one of the way to get timeline pins, another way is send pins to individual users directly, it’s not discussed here, but it is very similar.
There’s one caveat to begin using timeline – your app has to be enabled for it. In order to do this – you need to add compiled PBW of your app to developer portal and enable timeline for it. Note to test-run the timeline you don’t have to publish it, it just have to be in the portal with timeline enabled. Note also in timeline settings the API keys – you will need them soon. Once you added your app to the portal – run it, either on the watch or emulator. If you see ‘Subscribed to TestTopic’ in the logs – you’re good to go.

Ok, part 1 is done, now to part 2. I mentioned that it will be a very basic ASP.NET Web form and here’s full layout for it:

%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
    
        <asp:Label ID="Label1" runat="server" Text="Hours into the future: ">
        </asp:Label>
        <asp:TextBox ID="xtxtHoursIntoTheFuture" runat="server">
        </asp:TextBox>
        <asp:Button ID="xbtnSendPin" runat="server" 
            OnClick="xbtnSendPin_Click" 
            style="height: 26px" 
            Text="Send Pin" />
        <p>
            <asp:TextBox ID="xtxtResult" runat="server" 
                Height="187px" Rows="10" Width="329px">
            </asp:TextBox>
        </p>
    
    </div>
    </form>
</body>
</html>

As you can see, it’s a simple form that renders something like this:

Timeline form

In this test you enter number of hours in the future you want your pin to appear in the timeline, click “Send Pin” button and code in button click event sends the pin to the timeline. Pin has a very well defined JSON object format and this example sends following pin:

{ "id": "timeline_test_pin_2",
  "time": "2015-05-12T17:55:58.4098618Z",
  "layout": {"type": "genericPin",
              "title": "It's ALIVE!!!",
              "subtitle": "Wow, this voodoo works",
              "foregroundColor": "White",
              "backgroundColor": "Red",
              "body": "You pin is set successuffly!",
              "tinyIcon": "system://images/NOTIFICATION_FLAG"
            }
}

And here’s full C# code of the code behind the page that reacts on button click:

using System;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Net;


public partial class _Default : System.Web.UI.Page
{
    protected void xbtnSendPin_Click(object sender, EventArgs e)
    {
        // getting pin's time in UTC + added hours
        DateTime datetime = DateTime.UtcNow.AddHours(Convert.ToDouble(xtxtHoursIntoTheFuture.Text)); 

        //building pin
        JObject pin = new JObject(
            new JProperty("id", "timeline_test_pin_" + xtxtHoursIntoTheFuture.Text),
            new JProperty("time", datetime),
            new JProperty("layout",
                new JObject(
                    new JProperty("type", "genericPin"),
                    new JProperty("title", "It's ALIVE!!!"),
                    new JProperty("subtitle", "Wow, this voodoo works"),
                    new JProperty("foregroundColor", "White"),
                    new JProperty("backgroundColor", "Red"),
                    new JProperty("body", "You pin is set successuffly!"),
                    new JProperty("tinyIcon", "system://images/NOTIFICATION_FLAG")
                )
            )
        );

        //building web request
        string URL = "https://timeline-api.getpebble.com/v1/shared/pins/timeline_test_pin_" 
            + xtxtHoursIntoTheFuture.Text;

        using (var client = new System.Net.WebClient())
        {
            client.Headers.Add("Content-Type", "application/json");
            client.Headers.Add("X-API-Key", "insert_your_api_code_here");
            client.Headers.Add("X-Pin-Topics", "TestTopic");

            try
            {
                xtxtResult.Text = client.UploadString(URL, "PUT", pin.ToString());
            }
            catch (Exception i ex)
            {
                xtxtResult.Text = ex.Message;
            }
        }
    }
}

A bit of explanation:
Line 09 begins button click event handler
Line 12 calculates time of pin insertion by adding hours from input field to current date/time. Note usage of .UtcNow property – timeline requires date/time to be in Universal ISO format.
Lines 15-29 build pin JSON object. Here I am using widely popular JSON.NET library, that is now a part of VisualStudio and makes manipulating JSON extremely easy. Note that for pin ID I use simple text “timeline_test_pin_” + hours entered by user, in reality it has to be a bit more unique.
Lines 32-33 prepare URL of public Pebble timeline API (note pin ID is used here again)
Lines 35-49 issue actual API call. Note added headers – one for API Key (remember keys you saw in dev portal timeline settings? Insert one there: Either sandbox one for sideloaded watchapp or production one for app downloaded from the appstore). And the second header is pin topics – it should match topics subscribed by the watchapp.

When the page runs after button click – you will either see OK status upon successful pin submission or an error if something goes wrong (e.g. Bad Request if some parameters in JSON payload aren’t recognized). Once pin is send successfully go back to your watch and check the timeline – you will see the pin 2 hours from current time and if you open detailed view you will see screen pictured at the beginning of the post.

Leave a Reply

Your email address will not be published. Required fields are marked *