Friday 6 April 2018

Alexa, Open South Gloucestershire Bin Day


Another month, another Alexa skill that I've released to the wild. This was the skill that I teased back in Janurary on Twitter as the "useful" skill. The skill started off life with my main goal of retrieving information on my next bin collection as I kept forgetting what was being picked up each week (recycling, garden waste, non-recyclables). The skills available on the store were either for specific councils (not mine), or required me to set up the information my self. The problem with the latter is I'd be getting the wrong information if it ever changed without me knowing. I wanted to get the data straight from the source.

Luckily, my local council is South Gloucestershire and they are helpful enough to have the information available on their site (like most councils). Even better though their site seems to follow modern practices separating their services from their presentation layer, which meant I could use the same private APIs to retrieve the bin information. This meant that I could ask the council directly for this information and I developed this part of the skill quite early on. So why has it taken until now to release it?

Well, not content with just doing my council, I wanted to investigate if I could support other councils as well. I found a delightful API called api.postcodes.io, which allowed me to query the council that a given postcode was under. This was perfect for me to determine which council I had to query for the bin information for a given user. However, this is where my plans fell apart.

I started by looking at the number of councils available in England alone on Wikipedia. Turns out, there's a lot! So I decided to focus on the councils that served the most people and therefore my skill would be helpful to the most people. Unfortunately not all council websites are created equally and retrieving bin information are not designed as nicely as South Gloucestershire. Most of them are ASP based with server side rendering, which would mean that I would have to parse the website source code to get the information I needed. The result of this was fragile logic which could break if the website ever changed. In addition, the time it was taking me to get a single council up and running was taking ages with no guarantee it wouldn't suddenly break.

I'm surprised (and not surprised) with how different each council's website is structured, despite providing very similar information. I wish our government would have a common approach across councils as this make my life easier. Better yet would be a centralised service that provided common council information as this could save costs in the long run if there was just one set of services they'd have to maintain.

But back to the point of this post. If like me your local council (and number 50 on the list) is South Gloucestershire, you can grab my new skill from the Amazon store. If you do enable it, please don't forget to leave a review :)

Saturday 23 December 2017

Alexa, Open Bus Timetable


Over the past few years many of the big players have been pushing their own AI assistants. Cortana, Google Assistant, Alexa, Siri and more coming out every year. Recently, I've taken an interest in these different assistants, seeing how they tick and evaluating the similarities and differences. I see these as becoming the primary interaction for certain (but not every) day-to-day tasks that we may do now with other devices. For instance, last year I looked at asking Cortana for the latest temperature recorded by my Point devices.

Recently, I've obtained an Echo Dot as the price was just too low to pass up on. I'm impressed with it, and in the Kitchen, Alexa is very helpful when my hands are full. However, there was one piece of information she just couldn't provide to me out of the box.

I catch the bus a lot, but have just recently moved so haven't got used to the bus times. Alexa doesn't know this information out of the box, so I went looking for an existing skill to fill this void. Unfortunately, I failed to find one that either worked in my city (there's a lot that work in just London), or were natural/easy to use without having to know the stops I'm wanting to depart from. So I saw this limitation as an opportunity to expand my knowledge with the Alexa Skill framework and developed a skill where I could ask it more natural questions for finding out bus times.

But not wanting to limit this skill to just myself, I've soft launched it in the UK (with more countries to hopefully follow in the future) and so it's now available in the Amazon Skill Store. It would be great if you could try it out, provide feedback and rate it in the store :)

Friday 2 June 2017

Reminders in Microsoft Teams using Flow

Following on from my previous post, I thought I'd do another "solution" to a feature missing from Microsoft Teams that I used in Slack. Reminders.

In Slack, it was possible to set reminders within channels which Slack would remind you (or the channel) about at a given time. These reminders could be as simple as "remind @channel at 1pm to go to the meeting" or as complex as "remind @channel at 9am every weekday to go to standup".

This feature is unfortunately missing from Teams, with no bots available to fill the gap and nothing but a feature request to hold our breath on.

While we wait however, we can use Microsoft Flow to fill the gap.

(NOTE: There is currently a limitation with this guide around handles. Handles are currently not expanded when received by Teams, which means users belonging to that handle will not get notified. This is currently being worked on)

This tutorial will look into setting up a reminder; both simple and complicated. I'll be assuming that you know the basics of creating a flow, so lets get started by logging into Flow and select "Create from blank".

Setting up when our reminder goes off

Our flow will start off by setting up our schedule. This is achieved via the Schedule - Recurrence trigger. From here we setup our Frequency and Interval, which will be used to determine how often you want the reminder to go off. For instance, if you wanted the reminder to go off once a week, then you would set the Frequency to "Day" and Interval to "7" (i.e. every 7 days). In order to determine the day/time in which the reminder will go off, we'll need to look at the advanced options.


From here, we can setup a start date from when the reminder should start. This will also be the point in which our interval will initially be counted from. So if we wanted to have our reminder go off every Friday at 1pm, then our Start Time would be set to "2017-06-02T14:00:00". Note that you should adjust this to a date that falls on a Friday in the future, or the flow will never trigger :) You'll also want to setup a time zone to ensure it triggers based on your local time. For me, this is GMT (or UTC+0). Your trigger should look like the following.

Expanding our reminder

Our recurrence is fine if you want your reminder going off once a week or every day, but what if you wanted something more complicated? Something like our example where we want it every week day. In Flow, this is achieved via conditions.

To achieve this we'll need two conditions to make sure the day of the reminder is between Monday and Friday, which will need to be entered in advanced mode. The first condition should look like the following.

@greater(dayOfWeek(utcnow()), 0)

This condition is passing the current date/time into a function which returns the day of the week in the form of a number. 0 is Sunday, 1 is Monday all the way to Saturday which is 6. We are wanting this number to be greater than zero (Sunday), therefore starting on Monday.

From this condition, we'll then want to setup a second condition if the first condition is true/yes. This should look like

@less(dayofweek(utcnow()), 6)

This condition is similar to our first, but we want to make sure our day is less than 6 (representing Saturday), therefore ending on Friday. From here, all further actions will need to be added to the yes section of our conditions. The flow should look like the following:

Creating our reminder message

Once our Flow trigger goes off (and our conditions, if set up, are met), we'll want to compose our message to send a nicely formatted message to Teams. This can be done by adding an action following on from our trigger called Data Operations - Compose. Within the input field, we can then compose the message we want to send. This can include any supported markdown to create a formatted message (e.g. bold text).
In the example below, we're going to be posting "Stand up" in bold text

Sending To Microsoft Teams

The last part is to send our message to our desired channel within Teams. At the time of writing, Flow includes Teams integration directly, but there are two main problems that I have found when using it
  1. When Flow posts the data to Teams, it is posted on behalf of your account. This just looks odd to other users and I'm not sure if you'll get notifications when Flow posts on your behalf.
  2. The Teams integration doesn't support markdown for some reason. As this is still in preview, this will probably be fixed before final release.
Because of these problems, we're going to send our data to an incoming web hook made in Teams. Therefore, go to Teams and setup an incoming webhook. I like to give it a bit of style and therefore I've called it Flow Reminder with an alarm icon to make it stand out when posting.


Once done, copy the URL provided with the incoming web hook; we'll need this later on. In Flow, add a final action using HTTP - HTTP. The URI field should be set to the URL generated by the Team's incoming web hook. The rest of the action should look like the following:


As you can see, we're using Dynamic Content with our body. Dynamic Content are pieces of data that are generated as our Flow progresses and is based upon our previous triggers and actions and can be used in conjunction with fixed text. These are available in an overlay to the right of the action. They're added simply by tapping the relevant label.

Once complete give the Flow a name and save it. It's now ready to start sending you reminders in Teams. If you can't wait for the time to arrive, you can always run it manually.

Tuesday 23 May 2017

Richer Web Hooks With Microsoft Flow

I have recently started working with Microsoft Teams. Like other communication platforms, third party integrations make the platform ever more powerful. One integration I wanted was to alert members of the project I was working on when new builds were published to HockeyApp. With Slack, the integration was simple and produced an informative result within the target channels.

With Teams however, while simple to setup, the produced result is less than informative.



As you can see, less than seller. But not surprising, as Teams doesn't know how to interpret and display generic web hooks, as they all come in different shapes and sizes. Microsoft expects third parties to create custom connectors. Microsoft's next generation of HockeyApp (Mobile Center) has a connector on the roadmap, but nothing is expected to be done with HockeyApp.

To solve this problem, we need an intermediate interpreter that can take the content of our web hook and translate it into something that Microsoft Teams can understand and display. This can be achieved with a tool like Microsoft Flow and can be split down into three stages
  • Accept the contents of the incoming web hook
  • Translate
  • Send to Microsoft Teams
This tutorial will look into translating our HockeyApp web hook, but can be adapted to work for any service that supports web hooks. I'll be assuming that you know the basics of creating a flow, so lets get started by logging into Flow and select "Create from blank".

Setting up an Incoming web hook

First thing we need to do is set up an end point within Flow that HockeyApp can post our web hook notification to. Within the Triggers section, look for the trigger Request/Response - Request.

Once we've selected this trigger, we will need to tell Flow how to interpret the results so that it can use them later on in the flow. This can be done either by uploading a schema or by uploading an example response. For HockeyApp, we can get an example of the payload from their web hook tutorial, where we'll be using the payload of Version Released. Once uploaded, our result should look like the following.

An incoming web hook URL wont be generated until we've saved our flow, so we'll come back to this at the end.

Translating

Once Flow has received our incoming web hook, we'll want to translate the results into a nicely formatted message to send to Teams. This can be done by adding an action following on from our trigger called Data Operations - Compose. Within the input field, we can then format our web hook input into something more informative using the provided data. We do this by adding Dynamic Content to our input, which is available as an overlay to the right of the action. These variables are generated from our trigger's schema and can be used in conjunction with fixed text. They're added simply by tapping the relevant variable.

As our input will be used within Teams, our input will use markdown to stylise the content. I'm needing just the title, version and notes from HockeyApp, but you can include anything that is available to you. Our result should now look something like the follow.

Sending To Microsoft Teams

The final part of the puzzle is to send our formatted data to our desired channel within Teams. At the time of writing, Flow includes Teams integration directly, but there are two main problems that I have found when using it
  1. When Flow posts the data to Teams, it is posted on behalf of your account. This just looks odd to other users and I'm not sure if you'll get notifications when Flow posts on your behalf.
  2. The Teams integration doesn't support markdown for some reason. As this is still in preview, this will probably be fixed before final release.
Because of these problems, we're going to send our data to an incoming web hook made in Teams. Therefore, go to Teams and setup an incoming webhook. I like to give it a bit of style and therefore call it HockeyApp with the official logo to make it look official when posting.


Once done, copy the URL provided with the incoming webhook; we'll need this later on. In Flow, add a final action using HTTP - HTTP. The URI field should be set to the URL generated by the Team's incoming webhook. The rest of the action should look like the following:


As you can see, we're using Dynamic Content with our body, this time pointing at our generated payload from the translating stage to determine the content to send.

Finally give the Flow a name and save it.

Final Setup

So we have our flow, but now we need to configure our service, HockeyApp, to send data to it to start the flow off. Open up the Flow we've just created and select the first trigger. Now that our Flow has been saved, a URL should be generated within the HTTP POST URL field. Click the nice copy icon to copy it to your clipboard.

Once the endpoint URL has been copied, navigate to your service and setup the webhook. For HockeyApp, this can be done by following their tutorial, using the Flow URL as the target.

To test, you will either need to upload a new version to HockeyApp or use a tool like Postman to send an example payload to the URL generated by the flow. When you do either of these, you should see the new message pop up in Teams.


Friday 14 April 2017

Goodbye from Pix Casa

Hello fellow Pix Casa users!

I have decided that I will be ending support for Pix Casa and taking it off the marketplace. The app should still be "usable" for those of you that are currently using it for the time being, but no new users will be able to download it. I will no longer be providing updates or assist with any issues that are caused by the application. I suggest that you find alternative methods for viewing and backing up your photos.

This decision comes as the automatic backups have been less stable than they once were, and other users are also reporting similar issues. Without this key feature along with the reduced functionality of the app due to Google retiring Picasa, I don't see the same value the app once provided.

Thank you for supporting the app over the last two and a half years, which outperformed my initial expectations. I hope to see similar support for my current and any future projects I may release.

Monday 12 September 2016

My Daily Wallpaper v1.1 Out Now

 A new update has been released for My Daily Wallpaper bringing it up to v1.1. The aim of this update was to improve the experience of the initial release, as well as pave the way for new features coming in the future. New stuff includes:
  • New Source Settings - XKCD source now supports retrieving random comics. This means you can now have  different XKCD goodness every day of the week. Perhaps even make My Daily Wallpaper an XKCD app? Bing source now also supports downloading HD versions of wallpapers on mobile (and SD versions on desktop).
  • Live Tile Support! - My Daily Wallpaper now displays the last seven days worth of wallpapers straight on your start menu or start screen. This works in similar way to the native photos app.
  • Dislike - Dislike today's wallpaper from within the app. It doesn't do much at the moment other than give you tips, but I plan to do more with this in a future update
  • Change Is Good - When changing today's wallpaper source or source settings, you no longer have to wait to the following week to see those settings applied and instead can apply them then and there.
  • Updates To How Wallpapers Are Set - XKCD comic now has a reduced brightness when applied as a wallpaper to help make other text more readable. Improvements have also been made to how wallpapers are set in the background, which means it should be more reliable. 
Now that this update is out of the way I plan to start work on some new sources for the app as well as flesh out the dislike functionality to be more useful.

EDIT: If you have any ideas for future functionality you're wanting to see, I'd love to hear about it via appstretch.

Sunday 14 August 2016

UnauthorizedAccessException when deleting local files

While coding the first update for My Daily Wallpaper, I wanted to tackle some of the bugs reported by my users. According to the Windows Dev Dashboard, the top bug (by a long shot) was an UnauthorizedAccessException. Based on the logs this exception was caused by the wallpaper manager, which handles the downloading and setting of wallpapers based on user settings, where it would attempt to delete the old wallpaper.

foreach (StorageFile file in files)
{
    if (file.Name.StartsWith(LockscreenManager.OriginalFilenamePrefix, StringComparison.OrdinalIgnoreCase))
    {
        await file.DeleteAsync();
    }
}

The odd thing was, this error didn't occur all of the time and didn't have any clues as to why it did happen when it did.

I was stumped.

So I honed my Google-fu and managed to stumble upon a MS forum post which sounded a lot like mine.

It turns out, that when you reference a local file via the Image control in xaml, a lock is put on the file.

<Image source="Path/To/Local/File" />

This lock doesn't even seem to be taken off for while after navigating away from the page that includes said Image control.

The result - an UnauthorizedAccessException when attempting to delete the local file.

My solution to this problem is to use a converter to create the Source for the Image control by getting the file stream and loading it into a BitmapImage.

public class ImageSourceConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, string language)
    {
        string path = value as string;

        if (String.IsNullOrEmpty(path) == false)
        {
            var storageFile = StorageFile.GetFileFromPathAsync(path).AsTask().Result;

            var imageStream = storageFile.OpenStreamForReadAsync().Result;

            BitmapImage imgSource = new BitmapImage();

            imgSource.SetSource(imageStream.AsRandomAccessStream());

            return imgSource;
        }

        return null;
    }

    public object ConvertBack(object value, Type targetType, object parameter, string language)
    {
        throw new NotImplementedException();
    }
}