Monday, October 1, 2018

Example of Microsoft Flow usage or Flowers for my wife

Here I'll show you not so simple example of usage of Microsoft Flow for one practical task.

Sometimes programming challenges come from usual life. This was one of them. I want to buy flowers for my wife from time to time, e.g. once a month. But there is a catch. I don't want to do it on some specific date, like every first day of a month. In this case, it will not look like a surprise. I want some randomization. For example, next time to buy flowers should be in one month after the previous case plus/minus a couple of days.

There is nothing special about this requirement. It is easy to write a computer program, which will notify me of these events. But the desktop application will have a big drawback. It will work only on one machine, while I have several of them (at work, at home, ...). And a smartphone... Wouldn't it be great if I could get my notifications on any device I currently use?

Well, I can store information about events somewhere in an Internet database (like Mlab). In this case, all instances of my application will use and change the same information, that will allow them to work in sync. But still, I'll need to install this application on all my computers. Also, as I use Windows on computers and Android on the smartphone, I'll have to actually write different applications if I want to use them everywhere. How can I overcome this obstacle? With Web, of course.

If I'll create a Web application, I'll be able to use it on virtually any device I have. Great! It's decided, I must create a Web application. But still, it is not cool enough. Let me explain my point. Although it is not hard to write a Web application solving my problem, still there are many things I should care about. I must think about a hosting, about a storage for my data, about a code repository, ... And why? The functionality that I require is practically implemented in modern Web calendars like Google Calendar. It can create events, make them recursive, send notifications when the time has come, etc. The only thing it can't do is this randomization I want to have. Wouldn't it be cool, if I could just add this single feature and use all other features as well?

When I thought about this problem I came across a site IFTTT.com. The idea of this site is simple, yet powerful. If something happens, it makes something. I know, it sounds strange, so let me give you some examples. If I received an email from a specific person, send me an SMS. If my favorite author wrote a new article in his blog, inform me in Slack. Or if the time for some specific event has come in Google Calendar, send me an email. I hope, you see now where I'm going. This service can observe some events (they are called triggers) and take some actions when events happen. There are really tons of triggers and actions on IFTTT.com. I could watch my events on Google Calendar, and when a particular event occurs, I could send me an email, delete the old event from the calendar and recreate it at some later time. Great! This is what I need! But there are obstacles here as well.

First of all, IFTTT allows only one action for a trigger. This is not a big problem, as I can have several applets with identical triggers (an applet is a combination of trigger and action in IFTTT). One will send me an email, another will delete the old event from the calendar, and the last will create a new event there. But there is a bigger problem. For the new event, I must generate occurrence time randomly. And I have not found how to do it in IFTTT. It means, that this service can't solve my task. But maybe there are similar services on the Internet. And yes, there are.

The next service I came across was Zapier. Here we can create several actions for one trigger, which is good. But it is available only on paid plans, which is bad. I did not play with Zapier a lot, but it appeared to me that it also has no means to make the required randomization. I can be wrong here. Anyway, I moved to the next candidate.

It was Microsoft Flow. This service allows 750 trigger operations per month for free. It is more than enough for my needs. Moreover, it has the support of expressions, and there is rand() function! This is what I need. So let me show you how to solve the task with Microsoft Flow.

First of all, you should create a new flow. Flow is a combination of a trigger and actions. To do it, register on the site, click on "My flows", then click on "Create from blank":


Click on "Create from blank" button:


You'll be asked to select a trigger. Enter "calendar" in the search box and choose "Google Calendar":


In the list of available triggers for Google Calendar select "When an event starts":

Here you may be asked to authorize access of Microsoft Flow to your Google Calendar on your behalf.

Now your trigger is ready. The only parameter you should set is a calendar:

Yes, in Google Calendar you can create several calendars. Each event will belong to one calendar and you should choose the calendar, which events will trigger your actions.

It is completely fine to create a calendar and put there all events that should trigger your actions. But if not all events in the calendar should be processed, you may add filtering. Press "New step" and then "Add a condition":

A filter will be created for you. Now we should decide how we want to filter our events. For example, I only want to process events, that contains the text "[RANDOM]" in the location field. To do it, click on the "Choose value" text box. Microsoft Flow will show you a list of possible values you can work with:


Click on "Event List Event Location". Also, fill other text boxes with corresponding values:


Make notice the "Edit in advanced mode" link. It is very useful. If you click it, you'll get a presentation of the same condition in form of text expression:


It will be of great help when the time comes to write our own expressions.

Now we can add actions to our events. In the "If yes" branch of our filter click "Add an action" link. Here I'll create an action that sends me an email using Gmail:


As you can see, you can use data from our event to fill Subject, Body and other properties of the action.

Now we have our notification. It is time to delete old event in the calendar and create a new one on a later time. With help of "Add an action" link I'll create a "Delete an event" action for Google Calendar:



I want to make you aware, that it is possible to just update a calendar event instead of deleting and recreating it, but here I'll stick to the later strategy to illustrate one more possibility in Microsoft Flow. Let's say, I want my creation action to be executed not after delete action, but in parallel. Hover your mouse over the arrow between "Send email" and "Delete an event" actions. A plus sign will appear. Click on it and select "Add a parallel branch" -> "Add an action" from the context menu:


Now we can add a parallel "Create an event" action for Google Calendar. For this action, we'll take the title, description, and location from the initial event. The only one thing to do is to fill its start time and end time:


And now we come to the really interesting part. We need to add some random number of days to the start time of the event. And this new date we'll use as a start time for the new event. For example, I'd like to add 30 days plus/minus 2 days. One can find documentation about functions you can use here. I admit it is not a very easy text to read. I had many questions, especially about how to extract the start time of the initial event. Some help can be obtained from our condition action. Do you remember this "Edit in advanced mode" link:

 Click on this link will show the corresponding expression:


It gave me some help with the writing of my expressions. Now click on the "Start time" field of the "Create an event" action and choose "Expression" tab:



In the text box we can enter an expression like:

addDays(triggerBody()?['start'], add(30, rand(mul(2, -1), add(2, 1))))

and press the "Ok" button. It will solve exactly our task: add 30 days plus/minus 2 days. But what if I want some flexibility? What if I want to have several types of events. For the first type, I'd like to increase the start time by 30 days plus/minus 2 days, for the second type, I'd like to increase the start time by 14 days plus/minus 3 days, etc... How can I achieve this?

Here is the approach I have used. Do yoг remember, that we keep string "[RANDOM]" inside location fields of our events? Now I'll add some information to this field. It will contain text in the format "[RANDOM],NN,MM", where NN - two digits and MM - also two digits. I'll increase the start time of the event by NN days plus/minus MM days. In this case, I can be sure, that symbols 9 and 10 (starting from 0) of this string will represent NN and symbols 12 and 13 will represent MM. And here is an expression using this format to increase the start time of an event:

addDays(triggerBody()?['start'], add(int(substring(triggerBody()?['location'], 9, 2)), rand(mul(int(substring(triggerBody()?['location'], 12, 2)), -1), add(int(substring(triggerBody()?['location'], 12, 2)), 1))))

In general, it uses substring function to extract required parts of the string and int function to convert results into integers.

Cool! We are almost there. The only one thing to do is to set the end time of the event. And here we meet our last obstacle. I want the end time to be equal to the start time plus 15 minutes. Microsoft Flow has function addMinutes, and we can write something like this:

addMinutes(<the previous expression here>, 15)

But by the nature of the rand function, we can get here value, completely unrelated to our start time. Instead, I would like to have some variable 'nextStart' here, that will keep the value of our expression. In this case, I'll use this variable for the start time, and use

addMinutes(<the value of 'nextStart' variable>, 15)

for the end time of my new event. And you know what? Microsoft Flow has variables. First of all, we need to initialize one. Hover your mouse on the arrow between our trigger and condition. Click on plus sign and select "Add action":


Into the search box enter "Variables" and select "Initialize variable":


Set the name of the variable to 'nextStart' and type to "String". Microsoft Flow does not have a date/time type, so it uses string to represent date/time as well.


Now we can set value for the variable. I can't set it right here, as I don't know if this is a correct event. Only after our condition, I can be sure about it. So I'll insert another action of type "Set variable" after sending an email:


Here I set the value of the 'nextStart' variable to our long expression. The only thing left to do is to reuse this variable in expressions for the start and end time. We can reference our variable in expressions using:

variables('nextStart')

So expression for the end time of the event will be:

addMinutes(variables('nextStart'), 15)



This is the end of the story. We can save the flow and Microsoft Flow will run it for us.

I hope this article will be useful to you. I think that Microsoft Flow is a great tool for automation of different tasks.

No comments:

Post a Comment