File: luaplc.html

package info (click to toggle)
raritan-json-rpc-sdk 4.0.20%2Bds-2
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 57,236 kB
  • sloc: cs: 223,121; perl: 117,786; python: 26,872; javascript: 6,544; makefile: 27
file content (362 lines) | stat: -rw-r--r-- 30,491 bytes parent folder | download
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&amp;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&amp;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 &quot;Pdu&quot; module</div>
<div class="line">require &quot;Pdu&quot;</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(&quot;PDU Model Name: &quot; .. 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(&quot;Inlet &quot; .. label .. &quot; Current Reading: &quot; .. current .. &quot; A&quot;)</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(&quot;setSettings failed, rc = &quot; .. 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(&quot;10.0.42.3&quot;, &quot;user&quot;, &quot;password&quot;)</div>
<div class="line">pdu = pdumodel.Pdu:newRemote(&quot;/model/pdu/0&quot;, ha)</div>
<div class="line">print(&quot;Device Name: &quot; .. 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(&quot;/model/pdu/0&quot;, ha)</div>
<div class="line">print(&quot;Device Name: &quot; .. 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[&quot;outlet&quot;]  -- value for key outlet</div>
<div class="line">paramDelay = ARGS[&quot;delay&quot;]    -- 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 &quot;Pdu&quot;</div>
<div class="line"> </div>
<div class="line">-- my special exit handler</div>
<div class="line">function ExitHandler()</div>
<div class="line">    print(&quot;Exiting now&quot;)</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(&quot;error caught: &quot; .. msg)</div>
<div class="line">else</div>
<div class="line">    print(&quot;no error&quot;)</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 &gt; 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&#160;<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>