1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
<meta name="generator" content="Doxygen 1.9.1"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>Raritan / Server Technology Xerus™ PDU JSON-RPC API: LuaPLC</title>
<link href="tabs.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="dynsections.js"></script>
<link href="search/search.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="search/searchdata.js"></script>
<script type="text/javascript" src="search/search.js"></script>
<link href="doxygen.css" rel="stylesheet" type="text/css" />
</head>
<body>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<div id="titlearea">
<table cellspacing="0" cellpadding="0">
<tbody>
<tr style="height: 56px;">
<td id="projectalign" style="padding-left: 0.5em;">
<div id="projectname">Raritan / Server Technology Xerus™ PDU JSON-RPC API
</div>
</td>
</tr>
</tbody>
</table>
</div>
<!-- end header part -->
<!-- Generated by Doxygen 1.9.1 -->
<script type="text/javascript">
/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&dn=gpl-2.0.txt GPL-v2 */
var searchBox = new SearchBox("searchBox", "search",false,'Search','.html');
/* @license-end */
</script>
<script type="text/javascript" src="menudata.js"></script>
<script type="text/javascript" src="menu.js"></script>
<script type="text/javascript">
/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&dn=gpl-2.0.txt GPL-v2 */
$(function() {
initMenu('',true,false,'search.php','Search');
$(document).ready(function() { init_search(); });
});
/* @license-end */</script>
<div id="main-nav"></div>
<!-- window showing the filter options -->
<div id="MSearchSelectWindow"
onmouseover="return searchBox.OnSearchSelectShow()"
onmouseout="return searchBox.OnSearchSelectHide()"
onkeydown="return searchBox.OnSearchSelectKey(event)">
</div>
<!-- iframe showing the search results (closed by default) -->
<div id="MSearchResultsWindow">
<iframe src="javascript:void(0)" frameborder="0"
name="MSearchResults" id="MSearchResults">
</iframe>
</div>
</div><!-- top -->
<div class="PageDoc"><div class="header">
<div class="headertitle">
<div class="title">LuaPLC </div> </div>
</div><!--header-->
<div class="contents">
<div class="textblock"><p><a class="anchor" id="md__home_builds_gitlab_builds_QjAyd6bt_0_gitlab_main_firmware_mkdist_tmp_build_pdu_px2_final_documentation_json_rpc_api_lua_plc"></a></p>
<p><b>Lua</b> - A powerful and fast scripting language, simple to learn and use</p>
<p><b>PLC</b> - Programmable Logic Controller</p>
<p>The LuaPLC feature lets you write small programs and execute them directly on the PDU. Scripts can be deployed using the web GUI, via JSON-RPC or with USB flash drives. They can be started and stopped manually, triggered by event rules or scheduled with timer events.</p>
<p>Lua scripts have full access to the PDU data model as well as a few selected configuration interfaces. Additionally, scripts can use JSON-RPC to control remote PDUs.</p>
<h1><a class="anchor" id="autotoc_md138"></a>
Quickstart</h1>
<h2><a class="anchor" id="autotoc_md139"></a>
Requirements</h2>
<ul>
<li>A firmware with LuaPLC support (3.3.10 and later)</li>
<li>The Raritan JSON-RPC SDK</li>
</ul>
<h2><a class="anchor" id="autotoc_md140"></a>
Upload and Run a Lua Script</h2>
<ol type="1">
<li>Download the JSON-RPC SDK and unpack it</li>
<li>Open the device web GUI in a browser, login as administrator</li>
<li>Navigate to <em>Device Settings Lua Scripts</em>, click <em>Create New Script</em></li>
<li>Click <em>Load Local File</em> and select <em>pdu_info.lua</em> from the folder <em>LuaPLC_Examples/basic</em> in the SDK</li>
<li>Select a name for the script, e.g. <em>pdu_info</em></li>
<li>Click <em>Create</em> at the bottom of the page</li>
<li>On the script status page, click <em>Start</em>. The <em>Script Output</em> window should now show some information about the PDU.</li>
</ol>
<h1><a class="anchor" id="autotoc_md141"></a>
Writing Your Own Scripts</h1>
<h2><a class="anchor" id="autotoc_md142"></a>
Lua</h2>
<p>Lua is a powerful scripting language, easy to learn and simple to use. See the links section below to find about more the language itself.</p>
<h2><a class="anchor" id="autotoc_md143"></a>
Example Script</h2>
<div class="fragment"><div class="line">-- load the "Pdu" module</div>
<div class="line">require "Pdu"</div>
<div class="line"> </div>
<div class="line">-- acquire a proxy object for the pdumodel.Pdu interface</div>
<div class="line">pdu = pdumodel.Pdu:getDefault()</div>
<div class="line"> </div>
<div class="line">-- print the PDU model name</div>
<div class="line">metadata = pdu:getMetaData()</div>
<div class="line">print("PDU Model Name: " .. metadata.nameplate.model)</div>
<div class="line"> </div>
<div class="line">-- print the current sensor reading for each inlet</div>
<div class="line">inlets = pdu:getInlets()</div>
<div class="line">for _, inlet in ipairs(inlets) do</div>
<div class="line"> label = inlet:getMetaData().label</div>
<div class="line"> current_sensor = inlet:getSensors().current</div>
<div class="line"> current = current_sensor:getReading().value</div>
<div class="line"> print("Inlet " .. label .. " Current Reading: " .. current .. " A")</div>
<div class="line">end</div>
</div><!-- fragment --><p>There are a few details worth mentioning in the script above:</p>
<ul>
<li>Its first step is to load the <em>Pdu</em> module, and all modules it depends on. This module is required to use interfaces from the IDL-defined <em>pdumodel</em> namespace.</li>
<li>The next line uses the static method <code><a class="el" href="interfacepdumodel_1_1Pdu.html" title="Main PDU interface.">pdumodel.Pdu</a>:getDefault()</code> to acquire a proxy object for the <em><a class="el" href="interfacepdumodel_1_1Pdu.html" title="Main PDU interface.">pdumodel.Pdu</a></em> interface. This proxy object can be used to invoke the methods defined in the <em><a class="el" href="Pdu_8idl_source.html">Pdu.idl</a></em> file. It's the starting point for all scripts working with the PDU data model. All other PDU-related objects (inlets, outlets, sensors, etc.) can be acquired from here.</li>
<li>Next, the script invokes the <code>getMetaData()</code> method on the Pdu proxy object. Note the <code>:</code> character between object and method name, it's a critical part of the syntax! As defined in IDL, the call returns a <em><a class="el" href="structpdumodel_1_1Pdu_1_1MetaData.html" title="PDU metadata.">pdumodel.Pdu.MetaData</a></em> structure which includes the model name in the field <em>nameplate.model</em>.</li>
<li>In the following line, the script invokes the <code>getInlets()</code> method on the Pdu proxy. The method returns a list of proxy objects for the <em><a class="el" href="interfacepdumodel_1_1Inlet.html" title="Inlet interface">pdumodel.Inlet</a></em> interface defined in <em><a class="el" href="Inlet_8idl_source.html">Inlet.idl</a></em>. For a typical PDU with a single inlet, the list contains exactly one item.</li>
<li>The <code>for</code> loop in the next line iterates over the returned inlet proxies. <code>ipairs</code> is a Lua-builtin function that enumerates the elements in a list. For each iteration, it returns the index and value of the next list element. Since we're only interested in the value (the inlet proxy), we assign the index to a variable called <code>_</code>.</li>
<li>For each loop iteration, the variable <em>inlet</em> is updated to contain the next inlet proxy from the list. The loop body calls the methods <code>getMetaData()</code> and <code>getSensors()</code> on this proxy. Again, take note of the <code>:</code> syntax to invoke object methods.</li>
<li>Finally, the script selects the <em>current</em> sensor from the returned sensors structure. It contains a proxy for the <em><a class="el" href="interfacesensors_1_1NumericSensor.html" title="A sensor with numeric readings.">sensors.NumericSensor</a></em> interface. The script calls <code>getReading()</code> on that proxy to retrieve the latest sensor reading and prints the result to the script output.</li>
</ul>
<h2><a class="anchor" id="autotoc_md144"></a>
IDL to Lua Mapping</h2>
<p>The following table shows how IDL data types are mapped into Lua:</p>
<table class="markdownTable">
<tr class="markdownTableHead">
<th class="markdownTableHeadNone">IDL </th><th class="markdownTableHeadNone">Lua </th></tr>
<tr class="markdownTableRowOdd">
<td class="markdownTableBodyNone">boolean </td><td class="markdownTableBodyNone">boolean </td></tr>
<tr class="markdownTableRowEven">
<td class="markdownTableBodyNone">int </td><td class="markdownTableBodyNone">number </td></tr>
<tr class="markdownTableRowOdd">
<td class="markdownTableBodyNone">long </td><td class="markdownTableBodyNone">number </td></tr>
<tr class="markdownTableRowEven">
<td class="markdownTableBodyNone">float </td><td class="markdownTableBodyNone">number </td></tr>
<tr class="markdownTableRowOdd">
<td class="markdownTableBodyNone">double </td><td class="markdownTableBodyNone">number </td></tr>
<tr class="markdownTableRowEven">
<td class="markdownTableBodyNone">string </td><td class="markdownTableBodyNone">string </td></tr>
<tr class="markdownTableRowOdd">
<td class="markdownTableBodyNone">time </td><td class="markdownTableBodyNone">number </td></tr>
<tr class="markdownTableRowEven">
<td class="markdownTableBodyNone">enumeration </td><td class="markdownTableBodyNone">number </td></tr>
<tr class="markdownTableRowOdd">
<td class="markdownTableBodyNone">structure </td><td class="markdownTableBodyNone">table </td></tr>
<tr class="markdownTableRowEven">
<td class="markdownTableBodyNone">vector </td><td class="markdownTableBodyNone">table </td></tr>
<tr class="markdownTableRowOdd">
<td class="markdownTableBodyNone">map </td><td class="markdownTableBodyNone">table </td></tr>
<tr class="markdownTableRowEven">
<td class="markdownTableBodyNone">interface </td><td class="markdownTableBodyNone">table </td></tr>
</table>
<h3><a class="anchor" id="autotoc_md145"></a>
IDL Files</h3>
<p>Each IDL file is mapped to a Lua library that must be loaded with the <code>require</code> statement before use. For instance, to use the <em>Pdu</em> interface defined in the <em><a class="el" href="Pdu_8idl_source.html">Pdu.idl</a></em> file, use the statement <code>require "Pdu"</code>.</p>
<p>Loading a Lua library automatically loads all directly or indirectly referenced libraries. For instance, requiring the <em>Pdu</em> automatically includes many other modules, like <em>Inlet</em>, <em>Outlet</em>, <em>NumericSensor</em> or <em>PeripheralDeviceManager</em>.</p>
<h3><a class="anchor" id="autotoc_md146"></a>
Enumerations</h3>
<p>An IDL enumeration value is represented by a number in Lua. Additionally, there are constants for each element of the enumeration defined in IDL. For instance, to set the <em>startupState</em> field in the <em><a class="el" href="structpdumodel_1_1Pdu_1_1Settings.html" title="PDU settings.">pdumodel.Pdu.Settings</a></em> structure can be set to any of the values in the <em><a class="el" href="interfacepdumodel_1_1Pdu.html#ab69ff435e29ef72dd03833529cd92eed" title="Outlet power state on device startup">pdumodel.Pdu.StartupState</a></em> table:</p>
<div class="fragment"><div class="line">settings = pdu:getSettings()</div>
<div class="line">settings.startupState = pdumodel.Pdu.StartupState.PS_LASTKNOWN</div>
<div class="line">pdu:setSettings(settings)</div>
</div><!-- fragment --><h3><a class="anchor" id="autotoc_md147"></a>
Interface References and Methods</h3>
<p>References to IDL interfaces are represented by Lua tables containing the defined methods. To invoke a method, append the method name to the object reference separated by <code>:</code> character. IDL <em>in</em> parameters are mapped to required function arguments in Lua. Methods return a tuple of IDL-defined return value (unless <em>void</em>) and output parameters (if any).</p>
<div class="fragment"><div class="line">-- one in parameter, one return value</div>
<div class="line">rc = pdu:setSettings(settings)</div>
<div class="line">if rc ~= 0 then</div>
<div class="line"> print("setSettings failed, rc = " .. rc)</div>
<div class="line">end</div>
<div class="line"> </div>
<div class="line">-- no in parameters, three out parameters</div>
<div class="line">inlet, ocp, poles = outlet:getIOP()</div>
</div><!-- fragment --><h2><a class="anchor" id="autotoc_md148"></a>
Root Objects</h2>
<p>Root objects are the entry points for using the IDL-defined API. They are single instances of IDL interfaces that can be acquired using a static method (<code>getDefault()</code>, <code>getInstance()</code> or <code>new()</code>). References to other interfaces, like inlets, outlets and sensors, can be reached directly or indirectly from one of these root instances.</p>
<p>The following interfaces contain a static <code>getDefault()</code> method to acquire a root instance:</p>
<ul>
<li><a class="el" href="interfacecascading_1_1CascadeManager.html" title="JSON-RPC Cascade Manager.">cascading.CascadeManager</a></li>
<li><a class="el" href="interfaceevent_1_1AlarmManager.html" title="AlarmManager interface.">event.AlarmManager</a></li>
<li><a class="el" href="interfaceevent_1_1DataPushService.html" title="Data push service configuration interface.">event.DataPushService</a></li>
<li><a class="el" href="interfaceevent_1_1Engine.html" title="There is a single event engine instance reachable by a well known reference.">event.Engine</a></li>
<li><a class="el" href="interfaceevent_1_1Service.html" title="Event Service.">event.Service</a></li>
<li><a class="el" href="interfaceevent_1_1TimerEventManager.html" title="TimerEventManager interface.">event.TimerEventManager</a></li>
<li><a class="el" href="interfacefitness_1_1Fitness.html" title="Fitness Daemon interface">fitness.Fitness</a></li>
<li><a class="el" href="interfaceluaservice_1_1Manager.html" title="There is a single manager instance.">luaservice.Manager</a></li>
<li><a class="el" href="interfacenet_1_1Net.html" title="Network configuration interface.">net.Net</a></li>
<li><a class="el" href="interfacepdumodel_1_1OutletGroupManager.html" title="Outlet group manager interface.">pdumodel.OutletGroupManager</a></li>
<li><a class="el" href="interfacepdumodel_1_1Pdu.html" title="Main PDU interface.">pdumodel.Pdu</a></li>
<li><a class="el" href="interfacepdumodel_1_1PowerMeterController.html" title="Power Meter Controller (PMC) interface.">pdumodel.PowerMeterController</a></li>
<li><a class="el" href="interfacepdumodel_1_1Unit.html" title="Unit interface.">pdumodel.Unit</a></li>
<li><a class="el" href="interfaceres__mon_1_1ResMon.html" title="ResMon interface.">res_mon.ResMon</a></li>
<li><a class="el" href="interfaceserial_1_1PortDispatcher.html" title="Top-level interface of the serial port manager.">serial.PortDispatcher</a></li>
<li><a class="el" href="interfaceservermon_1_1ServerMonitor.html" title="Server Monitor Interface.">servermon.ServerMonitor</a></li>
<li><a class="el" href="interfacesmartcard_1_1CardReaderManager.html" title="Card Reader Manager Interface.">smartcard.CardReaderManager</a></li>
<li><a class="el" href="interfacesmartlock_1_1DoorAccessControl.html" title="Access control for door locks.">smartlock.DoorAccessControl</a></li>
<li><a class="el" href="interfacesmartlock_1_1KeypadManager.html" title="Keypad Manager Interface.">smartlock.KeypadManager</a></li>
<li><a class="el" href="interfacewebcam_1_1StorageManager.html" title="The storage manager interface.">webcam.StorageManager</a></li>
<li><a class="el" href="interfacewebcam_1_1WebcamManager.html" title="The webcam manager interface.">webcam.WebcamManager</a></li>
</ul>
<p>Some root objects require additional parameters and can be created with <code>getInstance()</code>:</p>
<ul>
<li><a class="el" href="interfaceserial_1_1AnalogModem.html" title="Interface for communication with an analog modem attached to a serial port.">serial.AnalogModem</a>:getInstance(portId)</li>
<li><a class="el" href="interfaceserial_1_1GsmModem.html" title="Interface for communication with a GSM modem attached to a serial port.">serial.GsmModem</a>:getInstance(portId)</li>
<li><a class="el" href="interfaceserial_1_1SerialPort.html" title="Interface describing a physical serial port and the devices which can be attached to it.">serial.SerialPort</a>:getInstance(portId)</li>
</ul>
<p>Lastly, the following objects are part of the system interface and can be created with a call to <code>new()</code> (possibly with additional parameters):</p>
<ul>
<li><a class="el" href="interfaceauth_1_1AuthManager.html" title="Authentication manager interface.">auth.AuthManager</a></li>
<li><a class="el" href="interfaceauth_1_1LdapManager.html" title="LDAP server configuration interface.">auth.LdapManager</a></li>
<li><a class="el" href="interfaceauth_1_1RadiusManager.html" title="RADIUS server configuration interface.">auth.RadiusManager</a></li>
<li><a class="el" href="interfacebulkcfg_1_1BulkConfiguration.html" title="Bulk Configuration Interface.">bulkcfg.BulkConfiguration</a></li>
<li><a class="el" href="interfacecert_1_1ServerSSLCert.html" title="TLS certificate management interface.">cert.ServerSSLCert</a></li>
<li>cfg.Cfg</li>
<li><a class="el" href="interfacedatetime_1_1DateTime.html" title="Date and time configuration methods.">datetime.DateTime</a></li>
<li><a class="el" href="interfacedevsettings_1_1Crestron.html" title="Crestron settings interface.">devsettings.Crestron</a></li>
<li><a class="el" href="interfacedevsettings_1_1Modbus.html" title="Modbus service settings interface">devsettings.Modbus</a></li>
<li><a class="el" href="interfacedevsettings_1_1Redfish.html" title="Redfish API service settings interface.">devsettings.Redfish</a></li>
<li><a class="el" href="interfacedevsettings_1_1Smtp.html" title="SMTP settings interface.">devsettings.Smtp</a></li>
<li><a class="el" href="interfacedevsettings_1_1Snmp.html" title="SNMP agent settings interface.">devsettings.Snmp</a></li>
<li><a class="el" href="interfacedevsettings_1_1Zeroconf.html" title="Zero-config service settings interface.">devsettings.Zeroconf</a></li>
<li><a class="el" href="interfacediag_1_1DiagLogSettings.html" title="Diagnostic log settings.">diag.DiagLogSettings</a></li>
<li><a class="el" href="interfacefirmware_1_1Firmware.html" title="Firmware management methods">firmware.Firmware</a></li>
<li><a class="el" href="interfacefitness_1_1HardwareHealth.html">fitness.HardwareHealth</a></li>
<li><a class="el" href="interfacelogging_1_1DebugLog.html" title="Device debug log interface.">logging.DebugLog</a></li>
<li><a class="el" href="interfacelogging_1_1EventLog.html" title="Device event log interface.">logging.EventLog</a></li>
<li><a class="el" href="interfacelogging_1_1WlanLog.html" title="WLAN diagnostic log interface.">logging.WlanLog</a></li>
<li><a class="el" href="interfacemodbus_1_1GatewayMgr.html">modbus.GatewayMgr</a></li>
<li><a class="el" href="interfacenet_1_1Diagnostics.html" title="Diagnostics interface.">net.Diagnostics</a></li>
<li><a class="el" href="interfacenet_1_1Services.html" title="Network services configuration interface.">net.Services</a></li>
<li><a class="el" href="interfacerawcfg_1_1RawConfiguration.html" title="Raw Configuration Interface.">rawcfg.RawConfiguration</a></li>
<li><a class="el" href="interfacesecurity_1_1Security.html" title="Security configuration interface">security.Security</a></li>
<li><a class="el" href="interfaceusb_1_1Usb.html" title="USB interface.">usb.Usb</a></li>
<li><a class="el" href="interfaceusermgmt_1_1RoleManager.html" title="Role manager interface.">usermgmt.RoleManager</a></li>
<li><a class="el" href="interfaceusermgmt_1_1Role.html" title="Role management interface">usermgmt.Role</a>:new(roleName) or <a class="el" href="interfaceusermgmt_1_1Role.html" title="Role management interface">usermgmt.Role</a>:new(roleId)</li>
<li><a class="el" href="interfaceusermgmt_1_1UserManager.html" title="User manager interface">usermgmt.UserManager</a></li>
<li><a class="el" href="interfaceusermgmt_1_1User.html" title="User interface">usermgmt.User</a>:new(userName)</li>
</ul>
<h2><a class="anchor" id="autotoc_md149"></a>
Remote Objects</h2>
<p>Remote objects are proxies that communicate with a remote object instance via JSON-RPC. Remote proxies can be created for any supported interface using the static <code>newRemote()</code> method. Expected parameters are a resource ID (URL suffix) and an HTTP agent (an object containing a reference to a remote PDU's JSON-RPC service).</p>
<p>The signature to create a new HTTP agent is: <code>agent.HttpAgent:new(host, user, password [, port [, useTls]])</code>. Required parameters are a host name or IP address, a user name and a password. Optional parameters are a port number and a boolean flag whether to use HTTP or HTTPS.</p>
<div class="fragment"><div class="line">ha = agent.HttpAgent:new("10.0.42.3", "user", "password")</div>
<div class="line">pdu = pdumodel.Pdu:newRemote("/model/pdu/0", ha)</div>
<div class="line">print("Device Name: " .. pdu:getSettings().name)</div>
</div><!-- fragment --><h2><a class="anchor" id="autotoc_md150"></a>
Accessing Link Units</h2>
<p>If the PDU is a cascade primary unit it is possible to communicate with remote object instances on the link units. This is done by using a remote proxy, created with the static <code>newRemote()</code> method as described above. As before, the expected parameters are a resource ID (URL suffix) and an HTTP agent. The HTTP agent for accessing a certain link unit in the cascade is created by calling <code>agent.HttpAgent:getForLinkUnit(linkId)</code>.</p>
<div class="fragment"><div class="line">ha = agent.HttpAgent:getForLinkUnit(2)</div>
<div class="line">pdu = pdumodel.Pdu:newRemote("/model/pdu/0", ha)</div>
<div class="line">print("Device Name: " .. pdu:getSettings().name)</div>
</div><!-- fragment --><h2><a class="anchor" id="autotoc_md151"></a>
Disconnecting HTTP Agents</h2>
<p><code>HttpAgent</code> uses keep-alive to maintain a built-up connection. While this has performance benefits, it also causes higher memory usage.</p>
<p>If you experience Out of Memory errors, you can try to prevent them by cleaning up unused HTTP connections via the <code>agent.HttpAgent:disconnect()</code> function.</p>
<h2><a class="anchor" id="autotoc_md152"></a>
Script Arguments</h2>
<p>Lua scripts can have arguments that are specified upon startup. Arguments are key-value pairs that can be accessed through the global table <code>ARGS</code>. Arguments can be specified persistently in the script options or using the "Start Script
with Arguments" function. Arguments passed at script start override the default arguments from the script options.</p>
<div class="fragment"><div class="line">paramOutlet = ARGS["outlet"] -- value for key outlet</div>
<div class="line">paramDelay = ARGS["delay"] -- value for key delay</div>
</div><!-- fragment --><h2><a class="anchor" id="autotoc_md153"></a>
Exit Handler</h2>
<p>If a script implements a global function named <code>ExitHandler()</code>, that function will be executed when the script stops unexpectedly, either because it crashes or is terminated. As a best practice, put this function at the top of the script (right after the require statements) and do not use any global variables within.</p>
<div class="fragment"><div class="line">require "Pdu"</div>
<div class="line"> </div>
<div class="line">-- my special exit handler</div>
<div class="line">function ExitHandler()</div>
<div class="line"> print("Exiting now")</div>
<div class="line">end</div>
</div><!-- fragment --><h2><a class="anchor" id="autotoc_md154"></a>
Delaying Execution</h2>
<p>The built-in sleep function can be used to pause the script for a defined time. The argument is specified in seconds, but fractional numbers are supported for sub-second delays.</p>
<div class="fragment"><div class="line">sleep(2) -- a 2 second pause</div>
</div><!-- fragment --><h2><a class="anchor" id="autotoc_md155"></a>
Exception Handling</h2>
<p>Without precautions, Lua scripts are terminated upon system errors in an IDL model calls (e.g. because using an object reference that doesn't exist). The built-in Lua function <code>pcall(f [, args...])</code> can be used to execute function <em>f</em> in protected mode. With pcall, the function to be called and its arguments must be specified separately. This includes the reference to the object the method should be invoked on, which must be passed as a first argument. The convenient syntax with <code>:</code> character cannot be used unless the method call is wrapped in an anonymous function:</p>
<div class="fragment"><div class="line">-- Correct use of pcall(): Pass object reference explicitly</div>
<div class="line">err, msg = pcall(outlet.setSettings, outlet, s)</div>
<div class="line"> </div>
<div class="line">-- Correct use of pcall(): Wrap method call in anonymous function</div>
<div class="line">err, msg = pcall(function() outlet:setSettings(s) end)</div>
<div class="line"> </div>
<div class="line">-- The following will NOT work:</div>
<div class="line">err, msg = pcall(outlet:setSettings(s))</div>
<div class="line"> </div>
<div class="line">-- test if error happens</div>
<div class="line">if err == false then</div>
<div class="line"> print("error caught: " .. msg)</div>
<div class="line">else</div>
<div class="line"> print("no error")</div>
<div class="line">end</div>
</div><!-- fragment --><h2><a class="anchor" id="autotoc_md156"></a>
Limitations</h2>
<p>There are some Lua script limitations:</p>
<ul>
<li>Number of deployed scripts</li>
<li>Script size (per script and total)</li>
<li>Memory usage per script</li>
<li>Script CPU utilization</li>
</ul>
<p>The actual limits can be queried using the <code>getEnvironment()</code> method of the <code><a class="el" href="interfaceluaservice_1_1Manager.html" title="There is a single manager instance.">luaservice.Manager</a></code> interface.</p>
<h3><a class="anchor" id="autotoc_md157"></a>
Out of Memory</h3>
<p>Memory usage per script is limited. A script allocating too much memory will be killed by the system. A message like <code>LuaSvcScript: Out of Memory. Aborting ...</code> is written to the script output.</p>
<h1><a class="anchor" id="autotoc_md158"></a>
Deploying and Running Scripts</h1>
<p>Scripts can be deployed via the following interfaces:</p>
<ul>
<li>Web GUI</li>
<li>JSON-RPC</li>
<li>USB Flash Drive</li>
<li>DHCP/TFTP</li>
</ul>
<h2><a class="anchor" id="autotoc_md159"></a>
Running Scripts from USB Drives</h2>
<p>In addition to uploading scripts to the PDU, script files can be executed directly from a USB mass storage device. You need to put the script on a USB drive, along with a control file called (for historical reasons) <em>fwupdate.cfg</em>. The control file needs to supply the administrator credentials and a reference to the script file:</p>
<div class="fragment"><div class="line">user=admin</div>
<div class="line">password=raritan</div>
<div class="line">execute_lua_script=my_script.lua</div>
</div><!-- fragment --><p>The script will be started as soon as the USB drive is plugged into the PDU. Any output will be stored in a separate log file on the drive. If the script is still running by the time the USB drive is disconnected it will be terminated. You can register an ExitHandler, but its runtime is limited to three seconds before the script forcibly is killed.</p>
<h2><a class="anchor" id="autotoc_md160"></a>
Running Scripts from DHCP/TFTP</h2>
<p>Running scripts from a TFTP server works similar to the USB drive method. Check the appendix in the PDU User Guide for details about the required configuration of the DHCP and TFTP servers. Runtime for scripts started via this method is limited to 60 seconds. Script output will be written back to the TFTP server, if the server allows it.</p>
<h2><a class="anchor" id="autotoc_md161"></a>
Starting Scripts with Event Rules</h2>
<p>Lua scripts can be started or stopped as an action in the event rules engine. Use the web GUI (<em>Device Settings > Event Rules</em>) to create a new action. Select <em>Start/Stop Lua Script</em> as action, then select the script you want to control.</p>
<p>Scripts started by an event rule will receive a number of arguments containing information about the matching event rule and the event triggering it. Arguments are stored in the global table <code>ARGS</code>.</p>
<h1><a class="anchor" id="autotoc_md162"></a>
Links</h1>
<p>Some Lua links:</p>
<ul>
<li><a href="https://www.lua.org">https://www.lua.org</a><ul>
<li>The offical Lua homepage. Includes a detailed reference manual.</li>
</ul>
</li>
<li><a href="https://www.lua.org/pil/contents.html">https://www.lua.org/pil/contents.html</a><ul>
<li>The online version of the book "Programming in Lua".</li>
</ul>
</li>
<li><a href="http://tylerneylon.com/a/learn-lua/">http://tylerneylon.com/a/learn-lua/</a><ul>
<li>Learn Lua in 15 minutes - more or less. To program with LuaPLC you need to know sections 1, 2 and 3. Sections 3.1 and 3.2 are nice to know.</li>
</ul>
</li>
<li><a href="https://en.wikipedia.org/wiki/Lua_(programming_language)">https://en.wikipedia.org/wiki/Lua_(programming_language)</a><ul>
<li>Wikipedia article about Lua. </li>
</ul>
</li>
</ul>
</div></div><!-- contents -->
</div><!-- PageDoc -->
<!-- start footer part -->
<hr class="footer"/><address class="footer"><small>
Generated on Mon Oct 17 2022 00:25:43 for Raritan / Server Technology Xerus™ PDU JSON-RPC API by <a href="https://www.doxygen.org/index.html"><img class="footer" src="doxygen.svg" width="104" height="31" alt="doxygen"/></a> 1.9.1
</small></address>
</body>
</html>
|