Skip to content

Scripting

adquio It allows automating tasks through scripting. You can react to any event and program the system for custom behavior using this feature.

Introduction to the operation of scripts

Each script is torn off at the time it is activated or when the appliance starts.

The handling of events or timed actions are obtained by instantanding handlers, which are small functions that will be executed as a response to an event or in a given time.

The integrated script editor

In the web interface of adquio you can list all scripts, activate them, deactivate them and edit its code.

The code editor includes a syntax checking system, which indicates grammatical errors and gives alerts in cases of uncommitted or ambiguous structures. Even so, it is not an infallible system and a script that does not show errors in the editor may not be correct.

More information in the chapter on the Graphic interface..

Types of scripts and self-generated blocks

There are three types of script in adquio. All of them represent a file that runs at the beginning of the system, only differ depending on their origin and the number of blocks they contain.

  • Generic scripts: Ready to be written by the Advanced User, with total freedom and a single block of code ("Main").
  • External scripts: Currently, if adquio is connected to Adquio Cloud, the script generated from Adquio Cloud by the user appears in this section.
  • Event scripts: In order to not have to deal with event handling in a generic script, you can link a script to a timer or event from other web interface views. They have three blocks:
  • Initialization: Block that is executed when starting the system.
  • Start of event: code block that runs each time the event is triggered, the interface already abstracts the instantiation of the handler and injects the code of this block.
  • End of event (only at events with duration): block of code that is executed when the event has ended.

Devices and variables

The devices and variables are accessed from the object devices.

From Devices you can operate directly on a variable:

const value = 2;
devices.write('device', 'variable', value);

You can also get references to devices and variables, to be used later, for example:

const DeviceA = devices.find('DeviceA');
const variable1 = DeviceA.findVariable('variable1');
const variable2 = devices.findVariable('DeviceA', 'variable2');
variable1.write(variable2.read() + 1);
variable2.write(DeviceA.read('variable3') - 1);

Note: If the variable/device obtained do not exist, its value is undefined, you should check the value before operating on them.

Note: Get a variable or device does not guarantee that at the time of operating these continue to exist or its status is functional. We could get a "variatenotfound" error over a variable already obtained.

Events

adquio It is designed based on events, events that are interesting for the programmer user are within the object events.

To react to an event, a handler is installing for that event with the function events.addListener(filter, handler), Once this function is executed, each time an event passes the filter will run the handler function that receives the event data.

Types of events:

  • Alert: New alert, expiration or existing alert update.
  • VariableChange: A variable has changed value.
  • Timer: Detects scheduled events, configurable from the web interface in the sectionProgramming.
  • VariableStatusChange: Change of a variable status.
  • DeviceStatusChange: Change of status of a device.
  • NewVariablesHistoric: New data set of the registered variables. Includes "aggregated" data or data collection in periodic samples.

From the graphical interface, the creation of events is simplified. In this way it is not necessary to hand the filter, see the section Event scripts for more information.

Defining the filter for events

The filter you select if a handle has to be called for a certain event can be of two types:

  • A function that receives EventData and resolves True or False. Other values will be converted to TRUE or FALSE according to JavaScript rules.
events.addListener(data => data.eventName === 'VariableChange' && data.variableCode.startsWith('UE'), data => {
  // Reaction to the event
});
  • An object, all fields that exist in the received object are compared. In order for the filter to be fulfilled, the filter fields must exist in the event data and be equal (using===):
events.addListener({
  eventName: 'VariableChange',
  variableCode: 'UE_01'
}, data => {
  // Reaction to the event
});

Defining the handler.

The handler can be any function defined by the user, which receives as the only parameter the object of the event. Each event has an identifier or EventName and fields that depend on the type of event.

In the help Side of scripts you can see the definition of the fields present in each type of event. The corresponding types finalize in eventdata on your behalf.

Example of visualization in the help of an eventData

For example, a handle could check the new value of a variable and if it does not meet a threshold, try to write a new value:

events.addListener({
  eventName: 'VariableChange',
  deviceCode: 'UE_01',
  variableCode: 'TSET'
}, data => {
  const variable = devices.find(data.deviceCode, data.variableCode);
  if(!variable) {
    //We record the error and leave the handler
    logger.error('Falta la variable UE_01#TSET');
    return;
  }
  if(data.newValue < 19) {
    variable.write(19);
  } else if(data.newValue > 25) {
    variables.write(25);
  }
});

Alerts

From the adquio scripts Alerts can be generated and managed. Alerts will then be displayed on the web interface, on the tab Alerts. Some alerts are sent to Adquio Cloud If integration is active, is the case of "equsalert" type alerts and those that contain one of the "System" or "Auto" tags.

Do touch() About an alert update your last check date. Field expireAfterMs defines how many milliseconds they pass before expirating automatically since an alert is executed create() or touch() the last time. If the expireafterms field is not defined, the alert does not expire automatically, in that case you can define an endtime (either in creation or updating it).

The method touchOrCreate() Search if there is an equivalent alert, if it exists it executes atouch() modify on it, if it does not exist create it. Two alerts are equivalent if the following fields are equal: type, payload, priority y owner.

Note: If an alert does not have defined expireafterms and the endtime value does not ever be established, the alert will remain active indefinitely. It is recommended to always establish a period for expireafterms` prudential to avoid that situation.

Example: Create a "personalized" type alert, with the specified data. Every 5 seconds is updated with the last value of the variable device#variable. As an expireafterms, it is greater that the update time, the alert will only expire if the system is restarted and the interval is not executed in the next 5 seconds:

setInterval(() => {
  alerts.touchOrCreate({
    priority: 10,
    type: 'Personalized',
    payload: {
      // The PayLoad can be any JavaScript serializable object, it is used to verify if two alerts are equivalent (that is, when looking for an existing one compares this field)
      description: 'Custom alert'
    },
    dynamicPayload: {
      // The DynamicPayLoad field works as a PayLoad that does not alter the identity of the alert. It serves to update dynamic data from the alert that we want it to remain the same (the touchorcreate function is going to update it and not create a new one)
      LastValue: devices.read('divice', 'variable')
    },
    // If the alert is not touched (touch) in 6 seconds, expires automatically
    expireAfterMs: 6000
  });
}, 5000);

Create an alert, regardless of whether there is already an equivalent. Then expire it once created:

const AlertA = alerts.create({
  priority: 10,
  type: 'Personalized',
  payload: 'Alert creation test',
  expireAfterMs: 1000
});
// We can make a touch of the new alert
alerts.touch(AlertA);
// Or force your expiration
alerts.expire(AlertA);

Alert fields

When an alert is defined, you can define the following fields:

Mandatory fields The alert is not generated and produces an error if they are not defined:

  • Priority: Number representing the importance of the alert, being 0 the highest possible priority (minor numbers indicate higher priority).
  • Type: text that brings together each alert within a common type. You can use any text, but it is recommended to group similar alerts in the same type to facilitate your understanding and search.

Optional fields:

  • expireAfterMs: Time in milliseconds that the alert will be active from the last touch () or from its creation. Once this time has elapsed, the alert expires automatically, defining the field endtime at the time of expiration. Note: Although the field is optional, it is recommended to specify it always, to avoid creating alerts that never expire, if you plan to expire them, specify a high value that does not interfere with that intention.
  • payload: Data relating to the alert, dependent on the type or user's intention. It allows to save a text string or a JS object. It can not change since it is part of the identity of the alert. For example, a low value alert, payLoad contains the identification of the variable that causes that alert.
  • dynamicPayload: Changing alert data. That is, the same alert can change these values without changing identity. For example, a value alert too low saves in dynamicpayload the most recent value, so that without changing the alert, the value can be updated.
  • tags: List of labels. Labels are short texts that classify alerts. There are two special labels system andequs; system generates critical system alerts, shown in red instead of yellow,equs generates alerts that are climbed to equs if it is active in the adquio.
  • endTime: If specified, define the time when the alert stops being active. It is not recommended its use in most cases, since there is the field expiraafterms to make alerts run a while without happening. Accept date or Timestamp.
  • startTime: If it is not specified, it is established at the current time. Moment from which the alert is active, defined as date or as Timestamp Numeric.
  • condition: watch Conditional alerts
  • onConditionError y onOutOfService: Action in case of error, watch Conditional alerts
  • delay: watch Alerts postponed.

Conditional alerts

You can define some fields that are not part of the alert in the functions of Create () and touchorcreate ().

The field condition establishes a condition that must be true for the alert to be created / updated. The condition can be a text that is evaluated by function calc () or a function, as seen in this example:

// Create condition using a formula in text
alerts.touchOrCreate({
  priority: 10,
  type: 'ConditionFormula',
  payload: 'Variable ext_temp of the device probes greater than 19',
  expireAfterMs: 30000,
  condition: '$probes#ext_temp$ > 19'
});
// Create condition through a function
alerts.touchOrCreate({
  priority: 10,
  type: 'ConditionFuncion',
  payload: 'Open entrance door',
  expireAfterMs: 30000,
  condition: () => devices.read('doors', 'entrance'),
  onOutOfService: 'alert'
})

The alert is only created if the formula or function returns true values.

Two options are also included to control behavior in case of errors:

  • onOutOfService Specify what it will be done if evaluating the condition involves accessing a variable that is out of service. If the value is not specified, it is "ignore".
  • onConditionError Specifies what will be done if evaluating the condition produces any other unneaked error. If it is not specified, it is "alert".

Possible values are (in all cases the original alert is not generated and the error is recorded in the logs):

  • ignore: Discard the error, however, it will be recorded in the logs.
  • alert: Generates an alert indicating the error happened.
  • error: Launch the error to be handled by the script.

Alerts postponed.

The postponed alerts allow to indicate in addition to a condition a period of waiting period (field delay), so that:

  • If the first time is created to the alert, the condition is met, another verification of the condition is postponed for the indicated waiting time.
  • If During the waiting period is again done touchorcreate () and the condition is no longer met. The second check is annulled and the alert is discarded without being created.
  • If in the check-down the condition is met, it is created, if the wait is not discarded and cancels.

In this way, if the alert is generated is because the condition has been true at least:

  • when calling for the first time in the script (without having a pending wait) and
  • after waiting for the indicated time and
  • All times in that period that has been called in the script

Note: By operating mode, it is not allowed to indicate the delay

The following example will create an alert if the variable doors#input is 1 and probes#input less than 18 for at least 10 seconds. However, it will take at least 10 seconds to do so. This check is performed every 5 seconds by Setinterval ().

setInterval( () =>
  alerts.touchOrCreate({
    priority: 10,
    type: 'ExamplePostponement',
    payload: 'The door takes open 10 seconds and it''s cold',
    expireAfterMs: 10000,
    condition: '($doors#input$ === 1) && ($probes#input$ < 18)'
  })
, 5000);

Formulas and evaluation

In some cases it can be practical or faster to be able to define assessments or conditions with a mathematical notation. For that the formulas are incorporated into the capacity of the scripts.

A formula plays a text and tries to evaluate it, allowing to represent the value of a variable of adquio with the notation $device code#variable code$. Allows common, mátematic operators and expressions in JavaScript, as +, -, <=...

To create a formula, install it using the Formula () function, on the result you can run EVAL () to obtain its value:

const myFormula = formula('$probes#exterior$ - 21');
const delta = myFormula.eval();
logger.debug('Delta is', delta);

In order not to handle a formula object, you can use the calc () method that directly returns the value of evaluating the formula, for example it could:

if(calc('$probes#exterior$ < 15')) {
  logger.debug('I am at' + calc('21 - $probes#exterior$') + ' degrees less than what I would like');
}

Note: Assignments or scriptures are not allowed within the formulas, formulas such as $dev#var$ = 5 are not valid.