An analytics domain specific language (DSL) for the Felix IoT platform

A Domain Specific Language for Analytics

Panini is the leading analytic function domain specific language (DSL). It allows developers, data scientists and tech. savvy business partners to quickly create and deploy new analytic functions and run them on the Felix real-time analytics engine. Panini makes it possible to enhance analytics capabilities in a matter of hours starting from conception through development, test and deployment.

Analytic functions developed using Panini can be deployed to a production system with zero (0) downtime. The Panini DSL makes the Felix IoT Platform infinitely extensible for very little cost and minimal configuration overhead.

About Panini

Panini, the DSL name, is derived from Panini (of Shalatula), a linguist and mathematician:

Panini (of Shalatula) (ca 520-460 BC) Gandhara (India)

Panini’s great accomplishment was his study of the Sanskrit language, especially in his text Ashtadhyayi. Although this work might be considered the very first study of linguistics or grammar, it used a non-obvious elegance that would not be equaled in the West until the 20th century. Linguistics may seem an unlikely qualification for a “great mathematician,” but language theory is a field of mathematics. The works of eminent 20th-century linguists and computer scientists like Chomsky, Backus, Post and Church are seen to resemble Panini’s work 25 centuries earlier. Panini’s systematic study of Sanskrit may have inspired the development of Indian science and algebra. Panini has been called “the Indian Euclid” since the rigor of his grammar is comparable to Euclid’s geometry.Although his great texts have been preserved, little else is known about Panini. Some scholars would place his dates a century later than shown here; he may or may not have been the same person as the famous poet Panini. In any case, he was the very last Vedic Sanskrit scholar by definition: his text formed the transition to the Classic Sanskrit period. Panini has been called “one of the most innovative people in the whole development of knowledge;” his grammar “one of the greatest monuments of human intelligence.”

The above content copied from:

Panini Features


While the Panini DSL workflow is implemented by the Felix Real-time Analytics Engine.  It can also be easily integrated into an existing analytic workflow enabling existing platforms to take full advantage of the Panini DSL features.

Canonical Workflow

Every analytic function will execute a simple workflow:

The DSL provides convenient hooks into this workflow that can be used by the creator of a new analytic definition.

Easy to Learn

Anyone with basic programming knowledge can learn to develop analytic definitions using Panini.  The complexity is isolated in the DSL implementation and never exposed the analytic definition creator.

Function Library

Out of the box, Felix provides an ever-growing set of analytic definitions including:

  • Continuous Min/Max
  • Debounce
  • Derivative
  • Dwell
  • Expression
  • External Min/Max
  • Moving Average
  • One-way Two Point Correlation
  • Totalizer
  • Two-way Two Point Correlation

An Example Panini Analytic Function Definition

To illustrate how easy it is to create analytic function definitions using the Panini DSL here’s an example:

This is an example of an analytic function definition that monitors how long a device is in a given state (dwell time) and raises an alert if the device remains in the state for longer than the specified threshold.

Using the Felix UI, an analytic context is created an bound to this definition to create an executable analytic function that monitors data from a source bound to the input parameter, sends results on channels bound to the output parameters and raises alerts bound to the alert parameters.

definition          'Dwell'
description         'Analytic block that captures how long a device is in a particular state'
version             '1.0'
ownerId             0

constant             name:'maxTrueMillis',     type:'long',        description:'The max number of millis the device should be in true state'
constant             name:'maxFalseMillis',    type:'long',        description:'The max number of millis the device should be in false state'

input                name:'monitor',           type:'boolean',     description:'The asset for which the dwell time will be monitored'

output               name:'trueTime',          type:'long',        description:'The current time the asset is in true state',        outputOnChangeOnly:true
output               name:'falseTime'          type:'long',        description:'The current time the asset is in false state',       outputOnChangeOnly:true
output               name:'trueExceeded',      type:'boolean',     description:'The true time threshold has been exceeded',          outputOnChangeOnly:true
output               name:'falseExceeded',     type:'boolean',     description:'The false time threshold has been exceeded',         outputOnChangeOnly:true

alert                name:'trueExceeded',                          description:'alert when thing state has exceeded the high threshold'
alert                name:'falseExceeded',                         description:'alert when thing state had exceeded the low threshold'

final long           DFLT_THRESHOLD = 5000,     

long                 maxTrueMillis
long                 maxFalseMillis

boolean              lastState
long                 lastStateTime

onBind {
    maxTrueMillis = constant.get 'maxTrueMillis' ?: DFLT_THRESHOLD
    maxFalseMillis = constant.get 'maxFalseMillis' ?: DFLT_THRESHOLD
    lastStateTime = 0

onInput 'monitor', {
    boolean currState = input.get 'monitor'
    long currStateTimestamp = input.getTimestamp 'monitor'
    // first reading for monitor so just set the values
    if( 0 == lastStateTime ) {
        lastState = currState
        lastStateTime = currStateTimestamp
    } else {
        if( currState != lastState ) {
            // T -> F
            if( lastState && !currState )
            handleStateChange lastStateTime, 'trueTime', maxTrueMillis, 'trueExceeded', 'falseExceeded', currStateTimestamp
            // F -> T
            if( !lastState && currState )
            handleStateChange lastStateTime, 'falseTime', maxFalseMillis, 'falseExceeded', 'trueExceeded', currStateTimestamp
            lastState = currState
            lastStateTime = input.getTimestamp 'monitor'

onTimerEvent {
    if( 0 != lastStateTime ) {
        long currTimeMillis = System.currentTimeMillis()
        if( lastState && ((currTimeMillis - lastStateTime) > maxTrueMillis) )
            createAlert 'trueExceeded'
        if( !lastState && ((currTimeMillis - lastStateTime) > maxFalseMillis) )
            createAlert 'falseExceeded'

void handleStateChange( lastStateTime, oldStateTime, oldStateMaxTimeAllowed, oldStateTimeExceeded, newStateTimeExceeded, stateChangeTime ) {
    long currTimeMillis = System.currentTimeMillis()
    long time = currTimeMillis - lastStateTime
    setOutputValue oldStateTime, time, stateChangeTime
    setOutputValue newStateTimeExceeded, false, stateChangeTime

    clearAlert newStateTimeExceeded
    if( time > oldStateMaxTimeAllowed )
        createAlert oldStateTimeExceeded
        clearAlert oldStateTimeExceeded

For more information, check out the Panini Language Dictionary

© Copyright 2021 IOT Technology Solutions, an STA Group company. All rights reserved. Privacy Policy.