Actions
Javascript » History » Revision 27
« Previous |
Revision 27/28
(diff)
| Next »
Torbjorn Carlqvist Admin, 05/29/2023 07:05 PM
Javascript guide for DTXr code IDE¶
Shows the various commands and events that can be used to build automation scripts.
NOTE, the below spec is 100% compatible with version 3.1.7. Ask DAVITOR for compatibility with previous versions or update your device.
Commands¶
//These two variable is used inside scratchPad function below for convinience.
//Set gThisDeviceId to what you have set (or got) for bacnet device id in the network!
//Set gRemoteDeviceId to any other device id on the network.
var gThisDeviceId = 123456;
var gRemoteDeviceId = 121212;
/** LOG/DEBUG **/
//Prints to console log window as well as autmation.log
//Note that automation.log is also written to by various services in DTX by
//default, not only what you do with print() in your code.
//Consider this as a volatile log where you debug and then clear from time to time.
//10Mbyte is max then it will rollover to time-stamped zip file and automation.log is cleared.
print("hello");
//Prints to automation_user.log
//This statement is the only source for loggin in this file.
//Consider this to be a persistant log of important process matters.
//10Mbyte is max then it will rollover to time-stamped zip file anf automation-user.log is cleared.
Controller.printToUserLog("hello user log");
/** BACnet related **/
//Translation helper for BACnet object ID->NAME
//Many even arguments are enumerated where theese function can help
print(getObjectTypeById(4)); //-> "binaryOutput"
print(getPropertyNameById(85)); //-> "presentValue"
// *** Write a value to an object property ***
// As you can see there is no syntax difference writing to local or remote objects.
//Local object
Controller.writeProperty(gThisDeviceId,analogValue,0,presentValue,priority_1,active);
//Remote object
Controller.writeProperty(gRemoteDeviceId,analogValue,0,presentValue,priority_1,active);
// *** Read a value from a property. ***
//Will return both primitiv and constructed (JSON) values
//Primitive
print(Controller.readProperty(gThisDeviceId,analogValue,0,presentValue));
print(Controller.readProperty(gRemoteDeviceId,analogValue,0,presentValue));
//Constructed (always JSON format from complex values)
//A priorityArray property is one example of constructed result
print(Controller.readProperty(gThisDeviceId,analogValue,0,statusFlags));
// *** COV Subscribtion ***
//With auto incremented process id, sensitivity (increment) of 1 (analog values) and subscription lifetime of 300s
Controller.COVSubscribe(covProcIncr,gRemoteDeviceId,analogValue,instance_0,noCovConfirmation,presentValue,1 /*sensitivity*/,300 /*lifetime (s)*/);
//With fixed process id 123, sensitivity (increment) no sesnitivity (binary values) and subscription lifetime of 300s
Controller.COVSubscribe(123,gRemoteDeviceId,analogValue,instance_0,noCovConfirmation,presentValue,null,300 /*lifetime (s)*/);
//UN-Subscribe with specific process id 10
Controller.COVSubscribe(123,gRemoteDeviceId,analogValue,instance_0,null,presentValue,defaultIncrement,null);
// *** Intrinsic Reporting (Alarms and Events) ***
//Remote Event Subscribe
Controller.eventSubscribe(gRemoteDeviceId/*device id*/,instance_0/*Notification Class*/);
//Enable event/alarm reporting on object
Controller.enableIntrinsicReporting(0/*NotificationClass*/,3/*delay*/,3/*delayNormal*/,analogValue,instance_0,notifyTypeEvent);
Controller.writeProperty(analogValue,instance_0,presentValue,priority_1,50);
//TextMessage
Controller.sendTextMessage(gThisDeviceId,"SOME_TYPE_OF_MSG","hello myself, what's up?");
//Acknowledge alarm and events
Controller.acknowledgeAlarm(gThisDeviceId,analogValue,instance_0,processIdZero,
ackNormal,1584383651150,"Toca",new Date().getTime());
//Issue an alert for a specific object via an Alert Enrollment Object
//The recipients in the notification class connected to the shosen alert enrollment object will receive the alert
var alertEnrollmentObjectInstance = 0;
var propretaryEventType = 666;
Controller.issueAlert(alertEnrollmentObjectInstance,analogValue,0,"To high!",propretaryEventType);
Controller.getEnrollmentSummary(gThisDeviceId);
//Send event notif local or remote nodes
//DeviceId,NotificationClass,AckRequired,Message
Controller.sendNotification(gThisDeviceId,0,1,"Coffe anyone?");
//Get all alarms for a specific device. Return JSON
resp = print(Controller.getAlarmSummary(gThisDeviceId));
//Get all events for a specific device. Return JSON
resp = print(Controller.getEventSummary(gThisDeviceId));
// *** Special Object Types *** //
//Read a range of datapoints from a TrendLog object
//The response is JSON with an array of value/timestamp
Controller.readRange(gThisDeviceId,trendLogMultiple,0);
// *** HTTP REST and Web Socket ***
//HTTP GET Request. Returns respons as string
resp = Controller.HTTP_GET('https://httpbin.org','get','Accept:application/json|Content-Type:application/json','myparam=hello');
//HTTP POST(also PUT and PATCH) Request. Return response as string
resp = Controller.HTTP_POST('https://httpbin.org/post'
,'Accept:application/json|Content-Type:application/json'
,'myparam=hello'
,'any payload string data');
//Web socket call to any webpage in the project file
//This require that the page has loaded the Ws.js import.
//Se HTTP Websocket template from the project tree sub menu
Controller.sendToWS("mypage","Hello My Page this is a payload");
//Connect to a Web Socket
//DTX has a built in single web socket client.
//Connect
Controller.connectWebSocket("wss://any.websocket.host");
//Send a message once connection is established
Controller.sendWebSocketText("Hello");
// *** SQL relational database access ***
//Note, SQL db is not embedded so JDBC config is made in settings in advance.
//Only PostgresSQL is supported for the moment!
//Simple query. Result (if any) will always be JSON!
print(Controller.sqlExecuteQuery("select * from anytable"));
//Inserts and updates are preferably solved with functions or procedures on
//the databas side. The CALL statement can then be utilized:
Controller.sqlExecuteQuery("CALL upsert_anytable("+name+",'"+age+"')");
//But of course a simple insert can also be sent...
print(Controller.sqlExecuteQuery("insert into anytable values('kalle','13')"));
// *** Timers and Schedulers ***
//Show all current jobs (including system jobs)
Controller.schedulerSummary();
//Pause all jobs
Controller.pauseAllJobs();
//Pause a specific job
Controller.pauseJob("JobA");
//Resume all jobs
Controller.resumeAllJobs();
//Resume a specific job
Controller.resumeJob("JobA");
//Start job
//Eg. executes function myCallbackFunction() with argument "df" after 10 seconds
Controller.startJob('Job1',10,'myCallbackFunction("df")');
//Eg. executes function myCallbackFunction() repeatedly every minute
//with a start delay of 5 seconds
Controller.startJob('Job2',5,60,'myCallbackFunction');
//Eg. start a CRON job that executes myCallbackFunction
//at 00:10 AM (10 minute past midnight) every day
Controller.startCronJob("Job3",'0 10 0 ? * * *','myCallbackFunction');
//Note: CRON can be difficult to construct.
//Use the below link to both crete and also verify your CRON strings.
//https://www.freeformatter.com/cron-expression-generator-quartz.html
//Cancel a job by using the name provided above
Controller.cancelJob("Job3");
//Cancel all jobs
Controller.cancelAllJobs();
//Cancel a specific jobs
Controller.cancelJob("JobG");
//This is a special function where you can schedule the execution of
//a code snippet.
//Arg1: Som job identifier - To use when pause/cancel the job if neccesary.
//Arg2: start delay (s) - Time until first exec
//Arg3: period(s) - Time between exec, set to 0 if no repetition is required/wanted.
//Arg4: repeates - Number of repeates, null if infinit, 0 if no repeat
//Arg5: code - Any Javascript
Controller.scheduleExecution("wait05",5,0,0,"print('print once in 5 sec');");
// *** MISC ***
//Send an email. Note, needs smtp-server config first
Controller.SendEmail("torbjorn.carlqvist@davitor.com","anysubject","some body");
// *** Embedded JSON storage ***
//Perfect to use when automation settings, states, structures etc must be persisted and
//the use of an external SQL database is unnecessary
//Push a string to spcified queue (queue will be created if not exist)
//This queue is persistant during reboot of the evice
//All queues and records are stored in the collection "jsonstore.json" which can be found in project folder
Controller.JSONPush("toca","msg5");
//Pop a string from the specified queue. FIFO!
//Returns null if no strings found
print(Controller.JSONPop("toca"));
print(Controller.JSONPersist("nisse"));
print(Controller.JSONPersist("1588058754445","palle"));
print(Controller.JSONRestore("1588058754445"));
print(Controller.JSONBrowse("toca"));
//Change name on multiple local objects
//This can be used when a group of objects need to have save name prefix.
//eg. when a sensor has multiple object and you want them to share same sensor name.
Controller.updateLocalObjectNames("TestBI","newname");
//This method should be used when javascript forms a link between
//an external interaface and the object stack.
//Typically when a button on a HMI should update an binaryInput or
//a reception of a BLE Beacon should update an analogInput.
//This method will create an object if no object exists with same profilName property
Controller.createOrUpdateLocalObject(analogInput,null,"MyObjectName",123);
//As an addition use this function to control the reliability of the obejct in real time.
//This will create events and alarms accordingly of intrinsic reporting is enanbled.
Controller.setLocalObjectReliability(binaryOutput,0,'shorted-loop');
Controller.setLocalObjectReliability(binaryOutput,0,'no-fault-detected');
//Yet another addition is this function to set the overridden flag on local objects.
//The meaning of this flag is to tell BACnet that this physical point is not
//longer reliable or commandable.
Controller.setLocalObjectOverridden(binaryOutput,0,true);
Controller.setLocalObjectOverridden(binaryOutput,0,false);
// *** File access ***/
//Basic file R/W/List for files in project folder (and sub folders)
Controller.writeFile("file_rw_test.txt","Hello file handling!");
print(Controller.readFile("file_rw_test.txt"));
print(Controller.listFiles(".txt",null));
print(Controller.listFiles(".json","mysubfolder"));
print(Controller.removeFiles(".txt",null));
// *** OS operations ***/
//Run commands on host operatice system
//Result is JSON string
//The exit_code tells if successful or not.
//There is a built in timeout if you accedently start a job that does not
//stop of it's own. Like doing unlimited ping on Linux
//No, there is no way to stop a command with Ctrl-C from JS.
//Note, the process is running in foreground so if DTX dies the process dies too.
print(Controller.execCommand("ping -n 3 google.com"));
// *** Serial Ports ***/
//List all connected serial ports. The response is JSON and can tell a lot
//about the serial port. For example in which USB socket it is connected.
print(Controller.listSerialPorts());
//Connect to a serial port (multiple connection is allowed)
//Use the serial port name from the response from listSerialPorts() above.
//As argument form a JSON according to specification.
//Example of setting up a serial connection to ttyACM0 that handles
//delimited responses with a "Return(0d)" at the END with a speed of 115200baud
//Note that if a connection already occurs in this name it will be closed automatically
Controller.setupSerialPort("ttyACM0",'{"msgDelim":true,"baudrate":115200,"delimPattern":"0d","delimPosition":"end"}');
//Send ASCII data to the connected port
Controller.writeSerialAscii("ttyACM0","hello");
//Send HEX data to the serial port
Controller.writeSerialHex("ttyACM0","03"); //Eg. Ctrl-C in HEX
//Close serial port
Controller.closeSerialPort("ttyACM0");
//NOTE: all received serial data enters the event callback "onSerialReceive"
/*** MODBUS ***/
/* Modbus TCP */
//If needed, use this to simulate a slave on THIS device for test purpose.
//Will setup a demo image of regs and coils
Controller.modbusTCPCreateSlave();
//Read coils (true/false)
//Args: Slave IP, Slave Port, Start Addr, Count
//Return: JSON Array with result
print(Controller.modbusTCPReadCoils("localhost",502,1,1));
//Reading input discretes (true/false)
//Args: Slave IP, Slave Port, Start Addr, Count
//Return: JSON Array with result
print(Controller.modbusTCPReadInputDiscretes("localhost",502,1,5));
//Reading input registers (Analog Inputs)
//Can be either signed or unsigned 16-bit values.
//Args: Slave IP, Slave Port, Start Addr, Count
//Return: JSON Array with result
print(Controller.modbusTCPReadInputRegisters("localhost",502,1,5));
//Reading holding registers (Analog Outputs)
//Can be either signed or unsigned 16-bit values.
//Args: Slave IP, Slave Port, Start Addr, Count
//Return: JSON Array with result
print(Controller.modbusTCPReadHoldingRegisters("localhost",502,1,5));
//Write to coil (!CAUTION!)
//Note, always returns null
//Args: Slave IP, Slave Port, Addr, Status (true=On/1, false=Off/0)
//Return: JSON Array with result (confirm)
print(Controller.modbusTCPWriteCoil("localhost",502,1,false));
//Writing to a holding registers (Analog Outputs)
//Can be either signed or unsigned 16-bit values.
//Args: Slave IP, Slave Port, Start Addr, Count
//Return: JSON Array with result (confirm)
print(Controller.modbusTCPWriteHoldingRegister("localhost",502,1,123));
/* Modbus Serial */
//Note, setting null as port settings defaults to 9600/8N1
//A mock-up test slave for serial modbus
//Args: Port, Port Settings, RTU
Controller.modbusSerialCreateSlave("COM1",null,false);
//Writing to a MODBUS slave coil via Serial RTU
//Args: Port, Port Settings,RTU,reg address, value/state
Controller.modbusSerialWriteCoil("COM2",null,false,2,true);
//Reading from a MODBUS slave coil via Serial RTU
//Args: Port, Port Settings,RTU,reg address
Controller.modbusSerialReadCoils("COM2",null,false,1,2);
/*** Controller management ***/
//Running reInit() will completly clear the JS-engine, stop all jobs and
//re-actiavate the code and finally call the init() method.
Controller.reInit();
Events¶
eventNotificationReceived - Called when an intrinsic report notification is received.¶
/**
* Called when controller starts. Good place to do init stuff
*/
function init(){
print("init!");
}
/***********************************************************************************************
* Called when the controller receives a notification (intrinsic reporting) from this or another device
* @param {processIdentifier} Can be used to process events/alarms different consumed. Users choice.
* @param {Number} initiatingDevice - The device ID that send the event and the device where the triggered object belongs
* @param {String} object - A convinient string to describe objectype:instance in text
* @param {Number} objectType - The source object of the event
* @param {Number} objectInstance - The instance of source object
* @param {Number} timeStampUTC - EPOC type of timestamp where the event/alarm trigger fired
* @param {Number} notificationClassInstance - An instance pointer to the connected class
* @param {Number} priority - Priority of this event
* @param {Number} eventType - The type of event received. Eg. 'outOfRange'
* @param {String} messageText - Free text that can be used describing the event
* @param {String} notifyType - Type of notification. Can be 'alarm' or 'event'
* @param {Boolean} ackRequired - Tell wether this event/alarm needs acknowledgment or not
* @param {String} fromState - The previous state
* @param {String} toState - The current state after the change
* @param {Object} eventValuesStr - A JSON object of specific values for this particular eventType
***********************************************************************************************/
function eventNotificationReceived(processIdentifier,initiatingDevice,object,objectType,objectInstance,timeStampUTC,notificationClassInstance,priority,eventType,messageText,notifyType,ackRequired,fromState,toState,eventValuesStr){
var eventDeviceName = Controller.readProperty(initiatingDevice,device,initiatingDevice,objectName);
var ncObjectName = Controller.readProperty(initiatingDevice,ObjectType.notificationClass,notificationClassInstance,objectName);
var eventObjectName = Controller.readProperty(initiatingDevice,objectType,objectInstance,objectName);
var summary = "Received " +eventType+" "+notifyType+" from "+eventDeviceName+" for object "+eventObjectName+" at "+new Date(timeStampUTC).toTimeString();
print(summary);
print("Current state:");
try{
var eventValues = JSON.parse(eventValuesStr);
for (var key in eventValues) {
if (eventValues.hasOwnProperty(key)) {
print(" - "+key + " " + eventValues[key]);
/*** Tip, enter code here to act on a specific key/value ***/
}
}
}catch(e){
print("eventValuesStr not JSON!")
}
if (notifyType === 'ackNotification' ){
var ackedstate = " - Acked state "+toState;
print(ackedstate);
summary = summary + ackedstate;
}else{
var transistion = " - State changed from "+fromState+" to "+toState;
print(transistion);
summary = summary + transistion;
}
print(" - Priority "+priority);
print(" - Ack required "+ackRequired);
if ( messageText !== undefined && messageText !== "")
print(" - Message "+messageText);
print(" - Class "+ncObjectName)
//Due to the standard, a notifying device does not save un-acked notifs
//transitions during reboot so it is best practise to make persistant on
//the receiver side.
Controller.printToUserLog(summary);
}
/*******************************************************************************
* Called when Change Of value Notification received from remote device
* In order to receive Change Of value notification the remote device must first
* be subscribed on the particular object instance.
* Eg. subscribe to Analog Input 0 on device 403
* - Controller.remoteCOVSubscribe(403,0,0);
* It is also possible to subscribe on local objects and in case of a local
* notification the device argument is null.
* Eg. subscribe on local Binary Value 1 and no increment (null)
* - Controller.COVSubscribe(0,0,null);
* @param {Number} epoch - A timestamp (nb of sec since 1970 kind of timestamp.
* @param {Number} processId - COV process id used by the requester in this subscription
* @param {Number} deviceId - Remote device that sent the notification
* @param {Number} objectType - The source object of the event
* @param {Number} objectInstance - The instance of source object
* @param {Number} propertyId - The instance of source object*
* @param {String} value - The new value.
*******************************************************************************/
function covNotificationReceived(epoch,processId,deviceId,objectType,objectInstance,propertyId,value){
print("covNotificationReceived - "+ "Process: " + processId + " Device: " + deviceId + " ObjectType: " +
objectType+" ObjectInstance: " + objectInstance + " propertyId: " + propertyId +
" New Value: " + value + " Time: " + new Date(epoch*1000));
}
/**********************************************************
* Called when the controller receives a HTTP GET request
* @param {String} resource - The REST resource
* @param {Object} params - The HTTP url parameters
*********************************************************/
function HTTP_GET(resource,params){
print(new Date().toISOString() + " HTTP GET - Resource: " + resource + " Params:" + params);
}
/**********************************************************
* Called when the controller receives a HTTP POST request
* @param {String} resource - The complete URI in the request
* @param {Object} payload - The HTTP header parameters
*********************************************************/
function HTTP_POST(resource,payload){
print("HTTP POST - Resource:" + resource + " Payload:" + payload);
}
/****************************************************************
* Called when a Web Socket request is made from a Web Client.
*
* @param {String} context - The key of the page
*
* The context can be made up by three parts URI + APP + SESSION
* where URI is the only mandatory part.
*
* @param {String} payloadTxt - The data sent from the WS-client
*****************************************************************/
function receiveFromWs(context,payloadTxt){
print("WS Callback from context "+context +" payload:\n" + payloadTxt);
/** This is a snippet to listen on Web Page Demo Template **/
/** Use it or remove it **/
if ( context.indexOf("page-demo") > 0 ) {
try{
var jsonObjPayload = JSON.parse(payloadTxt);
print(jsonObjPayload.msg);
print(jsonObjPayload.action);
//Answer to web page using incoming context
Controller.sendToWS(context,"Oh, Hi! I am a Web Socket request. Look for me in automation.js");
}
catch(e){
print("Err"+e);
}
}
}
/**
* Called when a BACnet object on this device changed.
* @param {type} objectType
* @param {type} objectInstance
* @param {type} propertyId
* @param {type} oldValue
* @param {type} newValue
* @returns {undefined}
*/
function localPropertyChanged(objectType,objectInstance,propertyId,oldValue,newValue){
//print('property changed on '+objectType+':'+objectInstance+' for prop '+propertyId +' where old value is '+oldValue +' and new value is '+newValue);
}
/**************************************************************************************************
* Callback when this controller receives a I Am notification from a remote device on the network
* @param {Number} device - Remote device that says hello
* @param {String} mac - The BACnet mac address of the sending device
**************************************************************************************************/
function iAmReceived(device,mac){
//print("IAM received from device:" + device + " MAC:"+mac);
}
/**************************************************************************************************
* Callback when this controller receives a BACnet private message request
* @param {Number} sourceDeviceId - Remote device that speeks
* @param {String} messageClass - See BACnet standard for usage. Could be use as any string data
* @param {String} messagePriority - See BACnet standard for usage. Could be use as any string data
* @param {String} message - Send message data
**************************************************************************************************/
function textMessageReceived(sourceDeviceId,messageClass,messagePriority,message){
print("textMessageReceived:"+message);
}
/***********************************************************************************************
* Called when the controller receives a write request from from a remote client
* on one of the local objects.
* @param {Number} objectType - The type of the object that is requested to be written
* @param {Number} objectInstance - The instance of the object that is requested to be written
* @param {Number} property - The property id that requested to be written
* @param {Number} priority - The priority of the value that is requested to be written
* @param {String} value - The new value
***********************************************************************************************/
function propertyWritten(objectType,objectInstance,property,priority,value){
print("propertyWritten - ObjectType: "+objectType+" ObjectInstance: "+ objectInstance + " Property: "+ property + " Priority: "+ priority + " Value: "+value);
}
/***********************************************************************************************
* Called when a file is put in file input directory
* The file input directory path is configured in setting page and is by default empty
*
* @param {String} fileName - The name of the file put in the file input directory
* @param {String} fileContent - The content of the file
*
* Note: There is special mapping for CSV file which are converted to JSON!
* Other file types are just received as is
***********************************************************************************************/
function receivedFile(fileName,fileContent){
print("Received file "+fileName+ " with content "+ fileContent);
}
/***********************************************************************************************
* Called receiving data on an activated serial port
*
* Note, see Controller.setupSerialPort(..) for activate a serial port
*
* @param {String} port - Wich port the data comes from
* @param {String} payload - The data
*
***********************************************************************************************/
function onSerialReceive(port, payload){
print("Serial data received on port: "+port+" data: "+payload);
}
/**************************************************************************
* This callback catches unexpected runtime errors like timeouts when
* writing or subscribing to a remote device currently absent.
* @param {String} type - Type or source of exception
* @param {String} message - Short description of the issue in plain text
* @param {String} details - Optional information in JSON format
**************************************************************************/
function exceptionCatch(type,message,details){
print("Exception catched, type:"+type+" message:" + message + " details:" + details );
}
/**
* When supported by the platform and enabled in the setting "beacon Station under Bluetooth"
* this method is invoked with advertisment from all Bluetooth LE devices nerby
*
* @param {String} mac - The sending Bluetooth device MAC adress
* @param {String} rssi - The signal strengh of the sending beacon
* @param {String} bt_payload - The beacon data
*/
function onBTBeaconAdvertising(mac,rssi,bt_payload){
//Example of whitelist filter
if( mac.includes("38FE") || mac.includes("CD8E")){
print("Beacon adv from mac: "+ mac + " rssi: "+rssi+" data:"+bt_payload);
//Here you can parse the payload from the beacon as you wish
//If the beacon is a Ruuvi, DTXr has a built in javascript library for the format 5
//See documentation on DTXr wiki
//https://collab.davitor.com/redmine/projects/dtxr/wiki
//More info on Ruuvi format and how to parse here
//https://ruuvi.com/custom-ruuvi-data-format-in-a-day/
}
}
/**
* Received an MQTT publish request
* @param {type} topic
* @param {type} payload
*/
function MQTTOnPublish(topic,payload){
print("MQTT client published " + payload + " on topic " + topic);
}
/**
* Received a web socket client text response
* @param {type} text
*/
function WebsocketOnClientReceiveText(text){
print("WebsocketOnClientReceiveText: "+text);
}
Updated by Torbjorn Carlqvist Admin over 1 year ago · 27 revisions