User Tools

Site Tools


scripts

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
Last revisionBoth sides next revision
scripts [2018/11/08 15:05] – [EnableConnection (connection_name)] emozolyakscripts [2019/01/09 10:29] akuzmuk
Line 1: Line 1:
-====== Lua scripts ====== 
-WebHMI allows you to create custom programs (scripts) in [[https://en.wikipedia.org/wiki/Lua | Lua]] 5.1 language. 
-There is a useful link for quick understanding  [[ https://gist.github.com/pateltej/bfec90ff449595f12236 | Lua in 15 minutes]].  
-The scripts are managed in the **Setup -> Scripts** menu item.  
- 
-Each script should contain a function named **main**. It will be called at the right time (depending on the settings of the script - in each cycle, when you act on the dashboard or when changing the value of the register, etc). Also, the entire script will be executed once when the daemon is started. This is necessary to compile the Lua script and validate it. Mis means that all the code that is in the global scope (that is, outside the main function, the main function will not be called) will be executed. This can be useful for initialising some variables, etc. 
- 
-Each script has its own global scope. It is impossible to access global variables and functions from one script in another. 
-  
-The **main** function will receive one parameter //userId//. This is ID of the user that executed this script. If the script is being executed in each loop or when the register is changed, **userId** will be zero. 
- 
-The example of a simple script for WebHMI: 
-<code lua> 
---[[ 
- these vars will be assigned only once 
- global var will keep their values between scans 
- BUT NOT between project restarts!!! -- use DSxxx registers for saving data between project restarts 
---]] 
-first_scan = true -- first scan flag  
-GLOBAL_CONSTANT_1 = 100 -- UPPER case preferrable for constants 
- 
-local now1 = 0 -- global because outside scope of main  
- 
-function main (userId) 
-       
-  now2 = 0 -- also global because no "local" before  
-          
-  if first_scan then  
-      first_scan = false  
-      -- some actions only made once upon project restart 
-  end  
-   
-  now1 = os.time () -- get time from Lua function  
-  now2 = GetReg ( "systemTime" ) -- get time form register with "systemTime" alias  
-               
-  if (now1 == now2) then  
-      DEBUG ( "both time are equal" ) 
-  else  
-      ERROR ( "something wrong with time ... " ) 
-  end  
-end -- main  
-</code> 
- 
-WebHMI imposes the following restrictions on standard Lua functions and libraries: 
- 
-  *such functions and tables are __not available__: require, print, loadfile, dofile, os.execute, os.getenv, os.remove, os.rename, os.tmpname, package , debug.debug, debug.getfenv, debug.getregistry, arg 
-  *libraries are __not available__: io 
- 
-In addition to the standard Lua functions, WebHMI also defines additional functions which are decsribed in their respective sections below.  
- 
-For the convenience of working with registers from Lua programs, each register can be assigned a symbolic name and be accessed from Lua already with this name. This name is specified in the register settings in the **Alias** field: 
- 
-{{ :alias_in_reg_list2.png?800 |}} 
- 
-In the example above, this name "systemTime" was used in GetReg function to read system time from internal WebHMI register with id = 1. 
- 
-An example of a simple script that shows the calls of some WebHMI functions: 
-<code lua> 
-function main (userId) 
-    local randomVal = GetReg("random_val"); 
-    SetReg("random_val_copy", randomVal); 
-    WriteReg("result", randomVal + 2); 
- 
-    AddInfoMessage("This is a Lua script", userId); 
-    AddWarningMessage("Warning. This is a Lua script", userId); 
-    AddAlertMessage("Alert! This is a Lua script", userId); 
- 
-    SendSMS("380501234567", "This is a test SMS"); 
- 
-    ERROR("This message will be added to communication log with ERROR level"); 
-    INFO("This message will be added to communication log with INFO level"); 
-    DEBUG("This message will be added to communication log with DEBUG level"); 
-    TRACE("This message will be added to communication log with TRACE level"); 
-end 
-</code> 
- 
-Despite the fact that the built-in editor checks the syntax of the program, it is not able to detect all the errors that can occur during the execution of the script. In the event that any errors occur during its execution, they will be displayed in communication log (**Maintenance->WebHMI Log**). 
- 
-For example, once this script will be executed, an error will occur because variable **random** is not declared. 
- 
-<code lua> 
-function main (userId) 
-     
-  local v1 = GetReg("Drying_Humidity1_Value"); 
-  v1 = v1+random; -- error is here, without random everything is ok 
-   
-  SetReg("Drying_Humidity1_Value", v1); 
-  WriteReg("Drying_Humidity1_Value", v1);  
-   
-  AddInfoMessage(v1, userId); 
-end 
-</code> 
- 
-There will be such records in WebHMI Log: 
- 
-<code> 
-Jan 23 12:09:27.047: ERROR: LUA scripts: Can't execute LUA script #1. Error #2: [string "Calculate humidity"]:4: attempt to perform arithmetic on a nil value (global 'random') 
-Jan 23 12:09:27.551: ERROR: LUA scripts: Can't execute LUA script #1. Error #2: [string "Calculate humidity"]:4: attempt to perform arithmetic on a nil value (global 'random') 
-Jan 23 12:09:28.051: ERROR: LUA scripts: Can't execute LUA script #1. Error #2: [string "Calculate humidity"]:4: attempt to perform arithmetic on a nil value (global 'random') 
-</code> 
- 
-Here we see that the error occurred while trying to perform an arithmetic operation with an undefined variable (value is **nil**). The error occurred in script number 1, its name was 'Calculate humidity', the error occurred in line number 4 at 12:09:27.047. The variable that caused the error is called 'random'. 
- 
-Thus, using this log you can find all runtime errors in your scripts. Also for debugging you can use watch console window, which is available in script editor. 
- 
- 
-===== Script Editor ===== 
- 
-Script editor allows you to write and manage scripts. The main editor's window: 
- 
-{{ :main_window2.png?912 |}} 
- 
-  - Script list 
-  - Selected script properties area 
-  - Code editor area 
-  - Edit tool buttons (full screen, insert function calls, show/hide console window, save) 
-  - Create new script button 
- 
-====  Script list (1) ==== 
-{{ :modified_disabled_script2.png?600 |}} 
- 
-The scripts run in the order how they are sorted in the list. This order can be easily changed by dragging a script into a new location. 
- 
-The line starts with the script **Id**. This number is shown in communication log to track the relevant script. E.g.  
-  Jul 26 17:23:27.450: ERROR: LUA scripts: Can't execute LUA script #3. 
- 
-Then goes title and two or three icons indicating type of script (see more details below), wether it has modifications, and its running state (Enabled/Disabled). In this example all possible types are shown with their respective icons.  
- 
-==== Property area (2) ==== 
-You can set here **name** for the script, select **type**, **disable** or **enable** it and give short **description**.  
- 
-There are 5 **types** of scripts: 
-  ***Execute in every loop** - script runs in every scan after reading registers in connections 
-  ***Script for dashboard** - script runs upon clicking the button with this script “attached” to it 
-  ***Execute on register's value change** - if there is difference of the register's value read in previous and current scan then script will be executed 
-  ***Script for calendar** - the script is set as start or end task action in the calendar 
-  ***Execute once on project start** - runs one time on the very first scan during project start 
- 
-==== Editor (3) ==== 
-WebHMI has handy code editor with useful features: 
-  * syntax highlighting  
-  * code completion  
-  * syntax validation 
-  * debugging console  
-  * supports a number of typical hotkeys  
- 
-Table of hotkeys: 
-^Key^Function^ 
-|F6|toggle compact / full-screen mode  | 
-|Crtl-S|save the script  | 
-|Ctrl-F|find and highlight occurence | 
-|Ctrl-H|find and replace | 
-|Ctrl-Z|undo | 
-|Ctri+Shift-Z|redo | 
-|Ctrl-A|select all | 
-|Ctrl-L|Select specific line | 
-|Ctrl-D|delete line | 
-|Ctrl-[ or Shift-Tab|decrease indent | 
-|Ctrl-] or Tab |increase indent | 
-|Ctrl-U|convert text to upper case | 
- 
-==== Editor toolbar (4) ==== 
-The toolbar has the following buttons (from left to right): 
- 
-  *Toggle full / compact screen mode button (hotkey: **F6**) 
-  *Insert GetReg call (will be explained further in GetReg function details) 
-  *Insert SetReg call 
-  *Insert WriteReg call  
-  *Show/hide console button 
-  *Save script (hotkey **Ctrl-S**) 
-  *Clone script button 
-  *Delete script button 
- 
-In the following picture, the full editor mode with console activated is shown: 
-{{ :editor_with_console.png?800 |}} 
- 
-==== Adding script (5) ==== 
-When there are no scripts yet in the project, the **+Add script** button is placed in the page center. After adding a script it is moved to the top-right page corner.  
- 
-===== Libraries ===== 
-Since version 3.2 you can create your own libraries. These are special scripts that can be included from other scripts so you can share the same code across multiple scripts. Use special keyword **include** to include another script. Provide script title as parameter to include call. Here is example: 
- 
-<code lua>  
-include "common.lua" 
-function main(userId) 
-  myCommonFunction(); 
-end 
-</code> 
- 
-Best practice it is to put include outside any function calls. Please note that global variables in libraries will not be shared across all scripts. Only code will be shared. 
  
 ===== Data-related functions ===== ===== Data-related functions =====
  
-==== GetReg(variable_name[, connection_name]) ==== 
-The GetReg function returns the current value of the specified register. 
- 
-Before version 3.2 following notation was used: 
- 
-The variable name **variable_name** where **variable_name** is the value of **Script alias** from the register's settings. Instead of variable_name you can specify a number - the register ID. However, the register ID is a less obvious way and it complicates the reading of the program. 
- 
-The optional parameter **connection_name** can be specified if in several different connections there are registers with the same **variable_name**. In this case, connection_name indicates from which particular connection it is necessary to read the register named variable_name. Also, instead of the string connection_name, you can specify the connection ID. However, again, constants complicate the reading of the code and it is preferable to use named lines. 
- 
-Since version 3.2 new enhanced notation used: 
- 
-There is no **connection_name** parameter anymore. **variable_name** is the only parameter. It can be in one of 3 following formats: 
-  - number with register Id. Not recommended to use because it is hard to read code with hardcoded numbers. Example: GetReg(12) 
-  - string with script alias of register. Example: GetReg("speed") 
-  - string in format "connection_alias.register_alias" where first part is connection alias and second part is register alias. Example: GetReg("mixer.speed"); In this example value or "speed" register from "mixer" connection will be fetched. 
- 
-If the register was not found or was not read, then the value **nil** is returned. 
- 
-For the convenience of selecting registers for GetReg, there is a special button in toolbar (4). 
- 
-{{ :get_reg_button.png?direct&300 |}} 
- 
-When you click on any of them, a pop-up window appears with a list of registers. 
- 
-{{ :select_register_dialog.png?direct&800 |}} 
- 
-After clicking on the register of interest, the editor will insert the code with the identifier of the selected register (variable_name if exists or ID) and a comment with the register name, its address and the connection name. 
- 
-{{ :reg_inserted_after_getreg.png?600 |}} 
- 
----- 
-==== GetRegStatus(variable_name) ==== 
-The GetRegStatus function returns the status of specified register. Function works exactly like function **GetReg**. 
- 
-On success function will return one of the following states: 
-  * unknown 
-  * disabled 
-  * normal 
-  * warning 
-  * alert 
- 
----- 
-==== GetRegFromLog(variable_name, query_parameters) ==== 
- 
-The GetRegFromLog function fetches data from register log. **varialbe_name** is an identified of register (see GetReg function for details). **query_parameters** is a table with up to 4 parameters: 
-   * from (unixtime, required) 
-   * to (unixtime, required) 
-   * order ("ASC" or "DECS, ASC is default) 
-   * limit (integer number between 1 and 5000, 1000 is default) 
- 
-Using these parameters WebHMI will construct query like: 
-SELECT * FROM log WHERE reg = //regId// AND datetime >= //from// AND datetime <= //to// ORDER by //order// LIMIT //limit// 
- 
-On success function will return table with register records from log database. Each row is a table with following records: 
-  * state (unknown, disabled, normal, warning, alert) 
-  * regid (integer) 
-  * time (unixtime) 
-  * value (string) 
- 
-Example: 
- 
-<code lua> 
-function tprint (tbl, indent) 
-  if not indent then indent = 0 end 
-  for k, v in pairs(tbl) do 
-    formatting = string.rep("  ", indent) .. k .. ": " 
-    if type(v) == "table" then 
-      ERROR(formatting) 
-      tprint(v, indent+1) 
-    else 
-      ERROR(formatting .. v)  
-    end 
-  end 
-end 
- 
-function main (userId) 
-    now = os.time(); 
-     
-    data = GetRegFromLog("myconn.myreg", {from = now-3600, to = now, order = "desc", limit = 10}); 
- 
-    tprint(data); 
-end 
-</code> 
- 
-Output: 
-<code> 
-Sep 13 17:37:25.098: ERROR: LUA scripts: 0:  
-Sep 13 17:37:25.098: ERROR: LUA scripts:   state: disabled 
-Sep 13 17:37:25.098: ERROR: LUA scripts:   regid: 1 
-Sep 13 17:37:25.098: ERROR: LUA scripts:   time: 1536849431 
-Sep 13 17:37:25.098: ERROR: LUA scripts:   value: 1 
-Sep 13 17:37:25.598: ERROR: LUA scripts: 1:  
-Sep 13 17:37:25.598: ERROR: LUA scripts:   state: disabled 
-Sep 13 17:37:25.598: ERROR: LUA scripts:   regid: 1 
-Sep 13 17:37:25.598: ERROR: LUA scripts:   time: 1536849410 
-Sep 13 17:37:25.598: ERROR: LUA scripts:   value: 0 
-</code> 
- 
----- 
-==== SetReg(variable_name[,connection_name], new_value) ==== 
-The SetReg function sets the current value of the register with the name of the variable **variable_name** to **new_value** for the current scan. This function **DOES NOT** send new value to external devices. When polling this register in subsequent cycles, the old value will be read.  
- 
-Function returns 1 if an error occurred and 0 on success. 
- 
-The parameters **variable_name** and **connection_name** work just like in the GetReg function. Since version 3.2 there is no more **connection_name** parameter. 
- 
----- 
-==== WriteReg(variable_name[, connection_name], new_value) ==== 
-The WriteReg function sets the current value of the register with the name of the variable **variable_name** (optionally you can specify the connection **connection_name**) to provided **new_value** for the current scan and writes this value to the external device in the beginning of the next cycle. When polling this register in subsequent scans, a new value will be read (if it was not changed by the device itself).  
- 
-Function returns 1 if any error occurred and 0 on success. 
- 
-The parameters **variable_name** and **connection_name** work just like in the GetReg function. Since version 3.2 there is no more **connection_name** parameter. 
- 
----- 
-==== ApplyRecipe(recipeId, userId) ==== 
-The **ApplyRecipe** function applies the recipe with the number **recipeId** on behalf of the user with id = **userId**. If this user does not have permissions for this recipe, the recipe will not be applied.  
- 
-The application of the recipe is to write the corresponding values to the registers that are specified in the recipe. 
- 
-==== GetRecipeById(recipeId) ==== 
-The **GetRecipeById** function gets the recipe with the number **recipeId**. Function is available since WebHMI v 3.2. 
- 
-On success table with following fields will be returned: 
-  * id - Recipe Id 
-  * title - Recipe title 
-  * registers - table with Register Id as key and new value as value 
- 
-On error (recipe not found, etc) false will be returned. 
- 
----- 
 ==== GetCurrentAlerts() ==== ==== GetCurrentAlerts() ====
  
Line 375: Line 54:
 </code> </code>
  
-===== Writing to communication log ===== 
  
-==== ERROR(message) ==== 
- 
-The function adds the **message** with the ERROR level to communication log (**Maintenance -> WebHMI Log**). Function returns 1 if any error occurred and 0 on success. 
- 
----- 
-==== INFO(message) ==== 
- 
-The function adds the **message** with the INFO level to communication log (**Maintenance -> WebHMI Log**). Function returns 1 if any error occurred and 0 on success. 
- 
----- 
-==== DEBUG(message) ==== 
- 
-The function adds the **message** with the DEBUG level to communication log (**Maintenance -> WebHMI Log**). Function returns 1 if any error occurred and 0 on success. 
- 
----- 
-==== TRACE(message) ==== 
- 
-The function adds the **message** with the TRACE level to communication log (**Maintenance -> WebHMI Log**). Function returns 1 if any error occurred and 0 on success. 
- 
-===== Writing to message log ===== 
- 
-==== AddInfoMessage(message, userId)==== 
-The AddInfoMessage function adds the message **message** with the Info level to the Messages log. **userId** is the user ID on whose behalf the message should be added. Returns 1 if an error occurred and 0 if successful. 
- 
-**AddWarningMessage** and **AddAlertMessage** - are full analogs of AddInfoMessage, writing to Warning and Alert message levels respectively.  
- 
-===== Notification functions ===== 
- 
-==== SendSMS(phone_number, message) ==== 
-The SendSMS function sends a request to send an SMS to the number **phone_number** with the text **message**. Returns false if an error occurred and true if successful. Success does not mean delivering a message, but only success when creating a query. This function requires an Internet connection, an account in [[http://docs.webhmi.com.ua/introduction_to_level2 | Level2]] system and a positive balance in it. The service is paid. 
- 
-Format of **phone_number** - only digits with the country code, without spaces, brackets, plus sign. For example, "380123456789". 
- 
-==== SendEmailMessage(emailAddress, subject, message) ==== 
- 
-The SendEmailMessage function sends a request to send an e-mail to **emailAddress** with the subject of the letter **subject** and the text **message**. Returns false if an error occurred and true if successful. Success does not mean delivering a message, but only success when creating a query. This function requires an Internet connection, an account in [[http://docs.webhmi.com.ua/introduction_to_level2 | Level2]] system and a positive balance in it. The service is paid. 
- 
-The field **message** can contain the html-code. 
- 
-Example: 
-<code lua> 
-function main (userId) 
-    SendEmailMessage("address@company.com",  
-               "Cooler malfunction. Low oil level.",  
-                "<p style='color: red;'>Cooler error #12 has occurred.</p><p>Низкий уровень масла.</p>"); 
-end 
-</code> 
- 
-The function is available since WebHMI 2.7.4710 version. 
- 
-==== SendTelegramMessage(chatId, message) ==== 
-The SendTelegramMessage function sends a message with the text **message** to the chat with Id = **chatId**. Returns 1 if an error occurred and 0 if successful. Success does not mean delivering a message, but only success when creating a query. To use this function, you must have an Internet connection, an account in the [[Introduction to Level2 | Level2]] system. The service is free. 
-To get ChatId, go to [[http://telegram.me/webhmibot]] on your mobile phone (by pre-installing Telegram) and start the dialog with bot webhmibot using the /start command. In response you will receive a message with a unique chatId. 
- 
-Example: 
- 
-{{ :telegram_screenshot.png?direct&400 |}} 
- 
-==== SendViberMessage(chatId, message) ==== 
-The SendViberMessage function sends a message with the text 'message' to the chat with Id = **chatId**. Returns 1 if an error occurred and 0 if successful.  
-Success does not mean delivering a message, but only success when creating a query. To use this function, you must have a working Internet connection, an account in the system [[Introduction to Level2 | Level2]] and a positive balance in this system. The service is chargeable. This feature is available starting with firmware version 2.4.4227.  
-To get ChatId, go to [[http://viber.com/webhmi]] on your mobile phone (having previously installed Viber), click 'Have a look' button. 
- 
-{{ :viber_1.png?direct&400 |}} 
- 
-You will be taken to the public WebHMI account. Go to the personal messages of the public account by clicking the button at the top right. 
- 
-{{ :viber_2.png?direct&400 |}} 
- 
-Write any text in the chat. In response you will receive a message with a unique chatId chat ID. 
- 
-{{ :viber_3.png?direct&400 |}} 
  
 ===== Weather and resource monitoring ===== ===== Weather and resource monitoring =====
Line 604: Line 210:
   *connection - ID or Lua name    *connection - ID or Lua name 
  
-==== DisableConnection(connection_name) ====+==== DisableConnection(connection) ====
 DisableConnection disables polling registers "on the fly" in the specified connection. The function is available since version 3.0. In the project configuration, the checkbox 'Disconnect' for the specified connection does not change. DisableConnection disables polling registers "on the fly" in the specified connection. The function is available since version 3.0. In the project configuration, the checkbox 'Disconnect' for the specified connection does not change.
  
-The connection_name parameter specifies for which connection the poll should be enabled. In connection_name, you can specify either the connection ID or its variable name. However, constants complicate the reading of the code and it is preferable to use named lines.+  *connection ID or Lua name 
  
-==== IsConnectionEnabled(connection_name) ====+==== IsConnectionEnabled(connection) ====
  
 The IsConnectionEnabled function tells whether the polling of registers in the specified connection is enabled. The function is available since version 3.0. The IsConnectionEnabled function tells whether the polling of registers in the specified connection is enabled. The function is available since version 3.0.
  
-The connection_name parameter specifies for which connection the poll should be enabled. In connection_name, you can specify either the connection ID or its variable name. However, constants complicate the reading of the code and it is preferable to use named lines.+  *connection ID or Lua name for the connection to be enabled
  
-==== GetConnectionErrors(connection_name) ====+==== GetConnectionErrors(connection) ====
  
 The GetConnectionErrors function reports whether there were errors while reading the registers in the last scan in the specified connection. The function is available since version 3.0. The GetConnectionErrors function reports whether there were errors while reading the registers in the last scan in the specified connection. The function is available since version 3.0.
 +
 +  *connectoin - ID of Lua name of the connection being checked
  
 If there were no errors, then the function returns zero. If there were errors, then the ID of the last register is returned, which was not read. If there were no errors, then the function returns zero. If there were errors, then the ID of the last register is returned, which was not read.
  
-The connection_name parameter specifies for which connection the poll should be enabled. In connection_name, you can specify either the connection ID or its variable name. However, constants complicate the reading of the code and it is preferable to use named lines. 
  
-==== GetConnectionScanTime(connection_name) ====+==== GetConnectionScanTime(connection) ====
  
 The GetConnectionScanTime function returns the time taken to poll the registers in the last scan in the specified connection. The function is available since version 3.0. The GetConnectionScanTime function returns the time taken to poll the registers in the last scan in the specified connection. The function is available since version 3.0.
 +
 +  *connectoin - ID or Lua variable name
  
 The function returns the time in milliseconds. The function returns the time in milliseconds.
  
-The connection_name parameter specifies for which connection the poll should be enabled. In connection_name, you can specify either the connection ID or its variable name. However, constants complicate the reading of the code and it is preferable to use named lines. 
  
-==== GetConnectionErrorScans(connection_name) ====+==== GetConnectionErrorScans(connection) ====
  
 The GetConnectionErrorScans function returns the number of consecutive scans in which there were errors reading the registers in the specified connection. The function is available since version 3.0. The GetConnectionErrorScans function returns the number of consecutive scans in which there were errors reading the registers in the specified connection. The function is available since version 3.0.
  
-The function returns the number of scans in which read errors occurred. If in any scan there were no read errors in this connection, the counter is reset to zero. +  *connection ID or Lua variable name 
- +
-The connection_name parameter specifies for which connection the poll should be enabled. In connection_name, you can specify either the connection ID or its variable name. However, constants complicate the reading of the code and it is preferable to use named lines.+
  
 +The function returns the number of scans in which read errors occurred. If in any scan there were no read errors in this connection, the counter is reset to zero.
  
 ===== Status ===== ===== Status =====

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki