Using the RouteCloud Node to Build a Route

The RouteCloud node is used to access the powerful RouteCloud route optimization tool. With this node you can:
 

Build entirely new routes (collections of ordered jobs at customer sites).
Sequence sets of existing routes.
Request a recommendation for the "best" (top N potential) insertion positions for stops on routes.
Insert a list of jobs onto routes without reordering existing stops.
Evaluate existing routes to determine arrival times at stops, costs, distances, breaks, and violations if any.

For information about the JSON formatting of requests, and for an in-depth overview of the features available to RouteCloud users, see the RouteCloud help. To use this node you must have suitable TDE authentication credentials.

Before we begin, it is important to understand the following:
 

The RouteCloud node natively performs all polling required until your optimization or routing task completes. Once you have provided an input, you only need to wait until the full output is returned. This may take seconds, or several minutes, depending on the complexity of the operation, but you do not need to perform any additional polling once it has started. If you were calling the RouteCloud API directly, from outside the Flows node, you would be required to poll the server to retrieve the results of an asynchronous operation. This is not necessary with the RouteCloud node.
Most users of this node should typically set the return_request field to true ("return_request": true) when supplying JSON-formatted data to the node. This flag requests that the RouteCloud API return the original input as the output. Without the return_request field, the RouteCloud API returns a new stop sequence, but not the original data on the stops. This can be more efficient if you are writing a UI, but a restriction if you want to pass this information on for further Flows node functions. Full documentation for return_request can be found here: https://routecloud.telogis.com/docs/guides/features/returning_full_request.html.

Using the RouteCloud Node in a Flow

The following example demonstrates a basic "build routes" call. We supply a JSON file describing three empty routes, including their durations, start and end locations, completion dates, maximum duration, and several required driver lunch breaks. This file also describes twelve jobs (job0 to job11) with details of their locations, required attributes and constraints. The "build routes" operation generates entirely new routes using this supplied collection of empty routes and jobs, and returns them as a formatted array.

In our example, we trigger the operation manually, and supply credentials directly to the routecloud node. In a production environment, you would typically pass credentials to the routecloud node as part of the message payload, for example from an http node.

Using the details we supply, RouteCloud attempts to assign as many jobs as possible to the three empty routes, while also minimizing their cost and respecting the constraints that we apply on the routes and jobs. If a job cannot be placed on a route, it is placed in the unrouted_jobs list. The complete steps needed to complete this tutorial are listed below, together with full JSON source code at the bottom of the page.
 

1.Sign in to Verizon Connect® Flows™ to open the Developer Console.
2.Click the Create flow button in the upper right corner of the screen. The Create Flow dialog box opens.
3.Select the Default button in the Revision Control section.
4.In the Flow name field, enter MyRouteCloud.
5.Select the Standard Flow radio button.
6.Click Create. The new flow is displayed at the top of the Developer Console.
7.Click the flow name (MyRouteCloud) to open it in the Flow Editor.
8.Drag an inject node from the utility section of the palette onto the canvas. We use this to manually launch the flow when it is finished.
9.Drag a template node from the advanced section of the palette onto the canvas. This node contains the JSON payload we pass to the RouteCloud optimizer. Connect the output of the inject node to the input of the template node.
10.Double-click the template node, and type a name into the Name field. For the purposes of this tutorial we use "routecloud json". Next, paste the following JSON text into the Template field. This message describes an array of empty routes, and an array of jobs to be assigned to these routes by the RouteCloud optimizer:

 

{

  "id": "routecloud_request",

  "return_request": true,

  "routes": [

    {

      "id": "route0",

      "location": "39.718005, -104.969531",

      "start_time": "09:00",

      "max_working_time": "08:00",

      "date": "2016-1-18",

      "breaks": [

        { "id": "route0_lunch_break", "start": "12:00", "length": "00:30" }

      ]

    }, {

      "id": "route1",

      "location": "39.718005, -104.969531",

      "start_time": "09:00",

      "max_working_time": "08:00",

      "route_attributes": ["hazmat"],

      "date": "2016-1-19",

      "breaks": [

        { "id": "route1_lunch_break", "start": "12:00", "length": "00:30" }

      ]

    }, {

      "id": "route2",

      "location": "39.718005, -104.969531",

      "start_time": "09:00",

      "max_working_time": "04:00",

      "date": "2016-1-20",

      "breaks": [

        { "id": "route2_lunch_break", "start": "12:00", "length": "00:30" }

      ]

    }

  ],

  "jobs": [

    { "id": "job0", "time_on_site": "00:10", "location": "39.635928, -105.049219" },

    { "id": "job1", "time_on_site": "00:10", "location": "39.725375, -104.791080", "date": "2016-1-18" },

    { "id": "job2", "time_on_site": "00:15", "location": "39.708990, -105.026954", "date": "2016-1-19" },

    { "id": "job3", "time_on_site": "00:10", "location": "39.653975, -105.093750", "allowed_dates": [ "2016-1-18", "2016-1-19" ] },

    { "id": "job4", "time_on_site": "00:15", "location": "39.590789, -105.084376", "allowed_dates": [ "2016-1-20" ] },

    { "id": "job5", "time_on_site": "00:10", "location": "39.638635, -105.128906", "required_route_attributes": [ "hazmat" ] },

    { "id": "job6", "time_on_site": "00:10", "location": "39.597111, -105.041015", "disallowed_route_attributes": [ "hazmat" ] },

    { "id": "job7", "time_on_site": "00:10", "location": "39.727919, -105.103126", "required_route_attributes": [ "heavy_truck" ] },

    { "id": "job8", "time_on_site": "00:10", "location": "39.615167, -104.887500", "time_window": { "start" : "13:00", "end" : "15:00" }  },

    { "id": "job9", "time_on_site": "00:10", "location": "39.820688, -105.133594" },

    { "id": "job10", "time_on_site": "00:10", "location": "39.749546, -105.069141" },

    { "id": "job11", "time_on_site": "00:10", "location": "39.556465, -104.976563" }

  ]

}

 
 

The request defines three routes:

 

route0, which starts on January the 18th at 9:00AM and has a maximum duration of 8 hours.
route1, which starts on January the 19th at 9:00AM, has a maximum duration of 8 hours, and provides the route attribute hazmat (hazardous materials).
route2, which starts on January the 20th at 9:00AM and has a maximum duration of 4 hours.
All routes start and end at latitude/longitude coordinates 39.718005, -104.969531 (a location in Denver, Colorado) and have a lunch break set at 12:00PM.

 

The request defines 12 jobs:

 

job0 is a simple job, with a location and a 10 minute time on site value. As job0 demands no further constraints, it can be placed on any route.
job1 and job2 define a required delivery date using the date field - job1 on the 18th and job2 on the 19th. These requirements dictate that job1 can only be placed on route0 and job2 only on route1.
job3 and job4 use the array syntax to define a set of allowed delivery dates. job3 can be delivered on the 18th or 19th, so can be placed on route0 or route1, while job4 can only be delivered on the 20th, so can only be placed on route2.
job5, job6, and job7 demand the following route attributes:
job5 requires the hazmat attribute so can only be placed on route1.
job6 disallows the hazmat attribute so cannot be placed on route1.
job7 requires the heavy_truck attribute which no route provides. It will, therefore, not be routed.
job8 defines a time window, which constrains the delivery of the job to between 1:00PM and 3:00PM. The job will be assigned to the route which can most efficiently satisfy this window.
job9, job10, and job11 define no complex constraints and will be placed on the routes which can most efficiently service them.

 

11.Click Done.
12.Drag a json node from the parser section of the palette onto the canvas, and then connect the output from the template node to the input of the json node. This node converts the json into a format that can be accepted by the routecloud node. We could, if we wanted, now connect to the routecloud node to perform a route build operation. However, we would also like to time the RouteCloud operation to see how long the task takes to complete, so we instead place the routecloud node between two stopwatch nodes: one set as a start and the second set as an end.
13.Drag a stopwatch node from the advanced section of the palette onto the canvas, and then connect the output from the json node to the input of the stopwatch node. Double-click the stopwatch node, and check that the Timer drop-down menu is set to "Start", then click Done.
14.Drag a routecloud node from the telogis section of the palette onto the canvas, and then connect the output from the stopwatch node to the input of the routecloud node. Double-click the routecloud node, and then enter your platform credentials and the RouteCloud operation endpoint:
 
a.In the Edit routecloud node dialog box, click the edit icon to the right of the Config field. If you do not already have a config defined, the Add new api-config node dialog box opens.
b.Under Source select "Enter customer credentials manually".
c.Enter your platform account information, including your Customer account name, your User name, and the Password for the account.
d.Select the Create authentication service token check box if you are adding a new api-config node.
e.Click Test connection. If the connection test succeeds, click Add or Update. If the connection fails and you are unable to resolve the problem, contact Verizon Connect customer support for assistance with your account details.
f.Open the Endpoint menu on the Edit routecloud node dialog box and select "/V1/build". When creating customer flows, this menu option is changed to the required RouteCloud operation, depending on the information you supply and the routing task you want to perform.
g.Click Done to close the Edit routecloud node dialog box.
 
12.Drag another stopwatch node from the advanced section of the palette onto the canvas, and then connect the output from the routecloud node to the input of the stopwatch node. Double-click the stopwatch node, and check that the Timer drop-down menu is set to "End". Click Done to close the editor dialog box. These two nodes, together, add a message to the payload detailing the RouteCloud operation completion time, together with the output from that operation. To check that these results are being returned, we now add a debug node to send any messages created to the console and the debug tab.
13.Drag a debug node from the utility section of the palette onto the canvas, and then connect the output from the second stopwatch node to the input of the debug node. Double-click the debug node, and check that the to drop-down menu is set to "debug tab and console". Click Done to close the editor dialog box.
14.Click the Deploy button in the upper right corner of the screen to deploy the flow, and then run the flow by manually launching the inject node (that is, click the light blue circular button to the left of the inject node). Open the debug tab to view a string message describing the length of time the RouteCloud operation took to complete the operation. Below this, an array response object describes the results of the build operation. For a detailed description of the formatting of this response, see Buidling Routes > Response. For suitable example files for sequencing, recommendation, insertion and evaluation RouteCloud operations, see the RouteCloud Help.

 

 

Source Code

 
The flow created in this tutorial is described by the JSON below. To successfully execute this flow, you must edit the routecloud node Config to add your own platform authentication credentials before you deploy.

To import a flow into the Editor, copy the code provided, click the upper right Menu button, then select "Import" > "Clipboard". Paste the code in the Import nodes window, then click Import.

 

Code:

[

    {

        "id": "13547d16.9e25e3",

        "type": "inject",

        "z": "254cf119.69911e",

        "name": "",

        "topic": "",

        "payload": "",

        "payloadType": "date",

        "crontab": "",

        "timezone": "US/Pacific",

        "once": false,

        "x": 400,

        "y": 260,

        "wires": [

            [

                "2974edc5.1c7612"

            ]

        ]

    },

    {

        "id": "4bfd05dd.67df4c",

        "type": "debug",

        "z": "254cf119.69911e",

        "name": "",

        "active": true,

        "console": "true",

        "complete": "payload",

        "x": 1400,

        "y": 460,

        "wires": []

    },

    {

        "id": "55d5cdbd.205c64",

        "type": "telogis-routecloud-api",

        "z": "254cf119.69911e",

        "name": "",

        "config": "fa8d5a03.d58ea8",

        "endpoint": "/v1/build",

        "x": 1120,

        "y": 360,

        "wires": [

            [

                "9a40074b.f494a8"

            ]

        ]

    },

    {

        "id": "2974edc5.1c7612",

        "type": "template",

        "z": "254cf119.69911e",

        "name": "routecloud json",

        "field": "payload",

        "fieldType": "msg",

        "format": "handlebars",

        "syntax": "mustache",

        "template": "{\n  \"id\": \"quick_start_build\",\n  \"return_request\": true,\n  \"routes\": [\n    {\n      \"id\": \"route0\",\n      
         \"location\": \"39.718005, -104.969531\",\n      \"start_time\": \"09:00\",\n      \"max_working_time\": \"08:00\",\n      

         \"date\": \"2016-1-18\",\n      \"breaks\": [\n        { \"id\": \"route0_lunch_break\", \"start\": \"12:00\", \"length\": \"00:30\" }\n      ]\n    }, {\n      

         \"id\": \"route1\",\n      \"location\": \"39.718005, -104.969531\",\n      \"start_time\": \"09:00\",\n      \"max_working_time\": \"08:00\",\n      

         \"route_attributes\": [\"hazmat\"],\n      \"date\": \"2016-1-19\",\n      \"breaks\": [\n        { \"id\": \"route1_lunch_break\", \"start\": \"12:00\", 

         \"length\": \"00:30\" }\n      ]\n    }, {\n      \"id\": \"route2\",\n      \"location\": \"39.718005, -104.969531\",\n      \"start_time\": \"09:00\",\n      

         \"max_working_time\": \"04:00\",\n      \"date\": \"2016-1-20\",\n      \"breaks\": [\n        { \"id\": \"route2_lunch_break\", \"start\": \"12:00\", 

         \"length\": \"00:30\" }\n      ]\n    }\n  ],\n  \"jobs\": [\n    { \"id\": \"job0\", \"time_on_site\": \"00:10\", \"location\": \"39.635928, -105.049219\" },

         \n    { \"id\": \"job1\", \"time_on_site\": \"00:10\", \"location\": \"39.725375, -104.791080\", \"date\": \"2016-1-18\" },\n    { \"id\": \"job2\", 

         \"time_on_site\": \"00:15\", \"location\": \"39.708990, -105.026954\", \"date\": \"2016-1-19\" },\n    { \"id\": \"job3\", \"time_on_site\": \"00:10\", 

         \"location\": \"39.653975, -105.093750\", \"allowed_dates\": [ \"2016-1-18\", \"2016-1-19\" ] },\n    { \"id\": \"job4\", \"time_on_site\": \"00:15\", 

         \"location\": \"39.590789, -105.084376\", \"allowed_dates\": [ \"2016-1-20\" ] },\n    { \"id\": \"job5\", \"time_on_site\": \"00:10\", \"location\": 

         \"39.638635, -105.128906\", \"required_route_attributes\": [ \"hazmat\" ] },\n    { \"id\": \"job6\", \"time_on_site\": \"00:10\", \"location\": 

         \"39.597111, -105.041015\", \"disallowed_route_attributes\": [ \"hazmat\" ] },\n    { \"id\": \"job7\", \"time_on_site\": \"00:10\", 

         \"location\": \"39.727919, -105.103126\", \"required_route_attributes\": [ \"heavy_truck\" ] },\n    { \"id\": \"job8\", \"time_on_site\": \"00:10\", 

         \"location\": \"39.615167, -104.887500\", \"time_window\": { \"start\" : \"13:00\", \"end\" : \"15:00\" }  },\n    { \"id\": \"job9\", \"time_on_site\": 

         \"00:10\", \"location\": \"39.820688, -105.133594\" },\n    { \"id\": \"job10\", \"time_on_site\": \"00:10\", \"location\": \"39.749546, -105.069141\" },

         \n    { \"id\": \"job11\", \"time_on_site\": \"00:10\", \"location\": \"39.556465, -104.976563\" }\n  ]\n}",

        "x": 660,

        "y": 260,

        "wires": [

            [

                "b0349c4b.faa3e"

            ]

        ]

    },

    {

        "id": "b0349c4b.faa3e",

        "type": "json",

        "z": "254cf119.69911e",

        "name": "",

        "x": 870,

        "y": 260,

        "wires": [

            [

                "a4380dd7.c7c76"

            ]

        ]

    },

    {

        "id": "a4380dd7.c7c76",

        "type": "stopwatch",

        "z": "254cf119.69911e",

        "action": "start",

        "message": "",

        "x": 920,

        "y": 360,

        "wires": [

            [

                "55d5cdbd.205c64"

            ]

        ]

    },

    {

        "id": "9a40074b.f494a8",

        "type": "stopwatch",

        "z": "254cf119.69911e",

        "action": "end",

        "message": "RouteCloud",

        "x": 1320,

        "y": 360,

        "wires": [

            [

                "4bfd05dd.67df4c"

            ]

        ]

    },

    {

        "id": "fa8d5a03.d58ea8",

        "type": "api-config",

        "z": "",

        "proxy": "",

        "instance": "production",

        "custominstance": "",

        "labelValue": "production - acme123:main",

        "useMessageCredentials": "false",

        "credentialsCustomer": "acme123",

        "credentialsUser": "main",

        "createAuthServiceToken": true

    }

]