Hello, Earl!
Author
Danilo Vidovic <dv@allthingstalk.com>
Date
November 16th, 2017
Description
Earl, ARL and stdlib: Tutorial, Specification, Documentation
Reviewers

AllThingsTalk Rules Language

AllThingsTalk Rules Language is a homegrown Domain Specific Language inspired by DOT.
It is compiled and executed by EARL, the rules engine. Execution is flow based, with data flowing from component outputs to component inputs. When writing ARL, the programmer is setting up the flow using components from ARL Standard Library, AllThingsTalk devices and connections between their outputs and inputs. The end result is somewhat similar to NodeRED.

  • In this document, terms “rule”, “flow” and “program” will be used interchangeably.

Tutorial

Let’s look at a problem of bridging an European IoT weather station that measures the temperature in degrees Celsius with a US made IoT weather display that - for the sake of the example - displays standard weather icons for temperatures received in degrees Fahrenheit.

The weather station is going to be modeled as an AllThingsTalk device with three sensors, for  temperature, pressure, and humidity. The display will be implemented as a device with a single actuator, fahrenheit.

To solve the problem, we need to monitor the temperature received from the weather station, convert the received value to degrees Fahrenheit, and pass it to fahrenheit actuator on the display.
The graphical representation above can be encoded textually as:

weatherStation = allthingstalk.device.ExampleId1
converter = allthingstalk.math.convert
fahrenheitDisplay = allthingstalk.device.ExampleId2

weatherStation.temperature -> converter.in
converter.fahrenheit -> fahrenheitDisplay.fahrenheit

What you see is most of the syntax you’ll ever see in ARL source code. Let’s look at what makes these programs tick more closely.

Components

In the program above, allthingstalk.math.convert, allthingstalk.device.ExampleId1, allthingstalk.device.ExampleId2 are components. 

Components are the building blocks of ARL programs. They are connected to other components through their inputs and outputs - ports. Everything that the program does, functionally, is computed within them. This applies to both the functions commonly found in standard libraries of various programming languages, as well as to mathematical operators, conditionals,  or looping constructs, which are usually regarded as features of the language syntax. The closest thing to components in standard languages are functions of multiple named arguments that return multiple named values. 

Earl comes with a standard library of components that can be connected to create rules regularly found in IoT scenarios. The component library can be extended either internally, or externally, by interfacing with Earl through HTTP.

Device Components
AllThingsTalk devices, like allthingstalk.device.ExampleId1, are also implemented as components. Their sensors map to outputs, actuators to inputs, and virtual assets can be used in both ways.

Component names
Component names are dot separated strings, like allthingstalk.math.converter or allthingstalk.device.ExampleId1. All parts preceding the final dot represent a namespace, which is currently used only for categorization. allthingstalk.device namespace is special, because the names following it represent device ids which in turn refer to components generated from these devices.

Instancing

To use a component in a rule, the component needs to be instanced, similarly how classes in OOP languages need to be instanced before being used. In ARL, this operation is done using the instancing operator =.

When instancing, the name on the left is bound to the new instance of the thing on the right.

weatherStation = allthingstalk.device.ExampleId1
converter = allthingstalk.math.convert
fahrenheitDisplay = allthingstalk.device.ExampleId2

The nature of returned instance is specific to the component implementation. Most components in the standard library create a new instance each time, making the component instances independent. If this didn’t work this way, stateful components like allthingstalk.state.counter would only be capable of holding a single value on the whole platform.