p44script short reference
Note: This short reference is built into your P44 device and is available offline without internet connection. For more technical documentation about p44script and advanced configuration, see the on-line technical documentation site instead.
It is available in German and in English.
About p44script
p44script is a specialized script language embedded entirely in your P44 device, including a full-featured integrated development environment (p44script IDE) and this short reference.
It has zero external dependencies and runs completely self-contained without internet access.
p44script has been designed to easily create reliable automations for lights, sensors, moving elements and much more in the context of a smart home installation, or as completely independent controllers.
p44script automations can run for years unattended, but can be easily maintained whenever a change is needed - no external tools required except for a web browser. Scripts written are part of the P44 device's configuration, are backed up with it and can easily be restored to another device in case of a hardware replacememt.
p44script in general has a syntax similar to Javascript or C, but comes with a set of features tailored for automation tasks which are unique and distinct from what Javascript offers. In particular, concurrent in-line execution and on()-handlers are powerful tools specific to p44script.
This page is not a tutorial - please visit the on-line docs and the plan44 user forum for additional material.
Comments are useful to add notes to source code explaining the code or important context to a human reader of the script or expression. Comments are ignored by the script engine, like empty lines and whitespace.
/* comment */
- C-style comment, starts with
/* and continues, possibly over multiple lines, until a */ is found
// comment
- C++-style single line comment, starts with
// and ends at the end of the same line
Literals
There are different ways to type numbers, text strings and some special values:
1234
- integer number, in decimal
0x89ab
- integer number in hexadecimal.
1234.567
- floating point number.
true or yes
- boolean true, numeric value is 1.
false or no
- boolan false, numeric value is 0.
null or undefined
- no value. Note that p44script has annotated null values, which means that in many cases, null/undefined also carries a short text describing its origin. This useful to debug as it helps understanding why a value is null/undefined. You can create annotated null values using the
null() function.
12:30
- time specification in hours and minutes. Numeric value is number of seconds since midnight.
13:30:22
- time specification in hours, minutes and seconds. Numeric value is number of seconds since midnight.
2.9.
- date specification in day.month. (period at end is important!) format. Example means 2nd of September. Numeric value is number of days from beginning of current year.
2.Sep
- date specification in day.monthname (no period at end!). Monthnames are jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec. Numeric value is number of days from the beginning of the current year.
wed
- weekday specification. Weekday names are sun, mon, tue, wed, thu, fri, sat. Numeric value is 0 for sunday, 1..6 for monday..saturday.
'text'
- String literal, use two single quotes in succession to include single quote.
"text"
- String literal with C-like escapes (
\n, \r, \t, \xHH and \\ can be used).
{ 'field1':42, 'field2':'hello' } // strict JSON
{ field1:42, field2:'hello' } // JavaScript style, field names do not need quotes
- objects with named fields.
[ 42, 43, 'hello' ]
- array.
Named Values
In expressions, named values (for example sensor values in evaluator conditions, or variables in scripts, see below) can be used. Simple values just consist of a name, but there are also structured values that can be accessed using dot and subscript notation, for example JSON data or objects/arrays.
sensor1
- the value of a sensor named sensor1.
sensor1.age
- the time in seconds since the sensor named sensor1 has been updated from hardware.
sensor1.valid
- true if the sensor named sensor1 has an actual valid value (a sensor that went into timeout or has never received data from hardware since the last restart does not have a value).
sensor1.oplevel
- a value between 0 and 100 indicating the "operation level" of the sensor. 0 means out of order, 100 means optimal conditions, values between indicate non-optimal conditions such as poor radio reception or low battery level. If no information is available, a null value is returned.
object.fieldA
- the subfield named fieldA in an object. So with object={ 'fieldA':42, 'fieldB':'hello' }, the result would be 42.
array[1]
- the array element at the numeric index 1 in an array array. The index is zero-based, so if array=[ 42, 'world' ], the result would be 'world'.
object['fieldB']
- the subfield named fieldB in a object object. So with object={ 'fieldA':42, 'fieldB':'hello' }, the result would be 'hello'.
object[0]
- the name of the first (index==0) subfield in a object. So with object={ 'fieldA':42, 'fieldB':'hello' }, the result would be 'fieldA'. This is how objects containing fields with unknown names (for example as returned by APIs) can be examined. The elements() function can be used to determine the number of fields in an object. Another way to go though all fields of an object is the
foreach statement, see below.
Operators
Operators are used to build expressions (calculations) from literals and named values (variables):
| Operator |
Precedence |
Description |
! |
6 (highest) |
logical NOT |
* |
5 |
multiplication |
/ |
5 |
division |
% |
5 |
modulo (remainder) |
+ |
4 |
numeric addition, string concatenation if left hand expression is of type string, array concatenation if both expressions are arrays, object fields merging if both expressions are objects. |
- |
4 |
subtraction |
== |
3 |
test for equal |
= |
3 |
test for equal (depending on context, = can also be an assignment, use == to avoid ambiguousness) |
!= or <> |
3 |
test for not equal |
< |
3 |
test for less than |
> |
3 |
test for greater than |
<= |
3 |
test for less than or equal |
>= |
3 |
test for greater than or equal |
& or && |
2 |
logical AND |
| or || |
1 |
logical OR |
:= |
0 (lowest) |
assignment |
= |
0 (lowest) |
assignment (depending on context, = can also be a test for equal, use := to avoid ambiguousness) |
++ |
0 (lowest) |
increments the variable on the left side (a++ is equivalent to the assignment a = a+1) |
-- |
0 (lowest) |
decrements the variable on the left side (a-- is equivalent to the assignment a = a-1) |
+= |
0 (lowest) |
add to the variable on the left side (a += 2 is equivalent to the assignment a = a+2) |
-= |
0 (lowest) |
subtract from the variable on the left side (a -= 2 is equivalent to the assignment a = a-2) |
*= |
0 (lowest) |
multiply the variable on the left side (a *= 2 is equivalent to the assignment a = a*2) |
/= |
0 (lowest) |
multiply the variable on the left side (a /= 2 is equivalent to the assignment a = a/2) |
Note that p44script does not have bitwise and/or operators, but instead provides the bit(), setbit() and flipbit() functions which provide bit(field) manipulation in a more intuitive way.
Variables
Local Variables
Local variables represent values that are local and private to a context where the script runs in. For example, in a P44-DSB or LC device, all scene scripts of a fixture run in a script context of that fixture, i.e. the scene scripts among themselves see the same local variables, but other fixtures or other devices do not have access to them (and therefore can use their own variables with the same name without conflicts).
Variables defined in a user function are private/local to that function. Variables defined with threadvar are even local to a single execution run (thread), even when the same code is run multiple times in parallel.
var a
- creates a scriptcontext local or function local (if used in a function) variable a (initially set to undefined. If a already exists, nothing happens.
var a = 7
- Definition of a scriptcontext local or function local variable a and assignment of an initial value. If the variable already exists, this is like a normal assignment.
threadvar t
threadvar t = 7
- Definition of a thread-local variable t (and assignment of an initial value if necessary). Unlike
var, this variable has a private value for each running execution thread (i.e. execution of an on(...) {...} or catch {...} handler, of which there might be more than one in parallel).
Automatically created thread variables
Thread variables are also created automatically by on(...) as var {...}, concurrent passing var {...} or catch as var {...}, since the value may be different for each (possibly parallel) run of such code.
(Whereas concurrent as var does not create a thread variable, but one in the context of the script that executes concurrent).
Global Variables
Global variables are values that can be written and read from any script in a P44 device under a common name.
Visibility of global variables
As global variables are visible from all scripts, it is recommended to use unique names that do not happen to occur by accident elsewhere as well. In general, global variables should be used sparingly and only when local variables are not sufficient.
glob g
global g
- declaration of global variable g. Declaration means that the name g is made known to all scripts in the device. Values assigned to g by one script will get accessible by all scripts. A global variable's value remains intact as long as the device runs (unless it is explicitly removed via unset, see below).
glob g = 78/9
- declaration and initialisation of global variable g.
- Note that the initialisation expression can only consist of constants or other global variables that are already defined.
Initialisation occurs once and before execution
Initialisation of global variables occurs only once, usually long before the script actually runs, when the script is first parsed by the p44script engine (at device startup or when a script is changed).
This can be confusing because when the script actually runs, all global variables are already initialized when the first script line executes, even if the initializer was written in the middle of the text. Furthermore, when multiple scripts try to initialize the same global variable with different values, only one can succeed.
To avoid confusion, it is good practice to put global variable declarations at the top of scripts, and use initializers only when really needed.
Assigning Values to Variables
a := 3*4
- Assignment of an expression's result to a.
a = 3*4
- single equal sign is also treated as assignment.
let a = 3*4
- let can be used to more clearly show this is an assignment (but is completely optional).
obj = {}
- create an empty object
obj.c = 7+8
- assign the expression's result to a field named c of the object variable obj. If the field c does not exist in obj, it will be created. Otherwise the former value of the field c will be replaced by the result of the expression.
arr = []
- create an empty array
arr[] = 6
- append the new element 6 to the array arr
arr[2] = 7
- assign 7 as the 3rd (not the 2nd, array indices are zero based!) element of the array arr
obj = {
a: 42, b:'a string', c:[ 1, 2, a*2], d: { n:1, sin:sin(a), ["a_is_"+a)]:13 }
}
- complex object/array structures can be created and multiple fields assigned expressions in a single statement. Even field names can be created from expressions by enclosing them in square brackets (see last field in the example).
Deleting Variables
unset b
- removal of a (local or global) variable named b.
unset a.b
unset a['b']
- removal of field b from object variable named a.
unset c[2]
- removal of element with index 2 (= third element) from an array named c.
Multiple Script Statements
a = 7; b = 3; c = a*b;
- multiple statements can be written on a single line separated by semicolons.
{ a = 42; b = 23; scene(_'bright'_); }
- block (group) of multiple statements
Control Flow
Conditionals
if (a>0) b := 7
- conditional execution of the assignment b:=7 when a is greater than zero.
if (a>0) b := 7 else b := 19
- conditional execution of the assignment b:=7 with else statement which is executed when condition is not true.
if (a>0) { b := 7; c := 44 } else { b := 0; c := "a string }
- conditional with statement blocks.
Loops
while (i>0) { i := i-1; log(5, "i is now: " + i); }
- repeat (loop) statement block as long as i is greater than zero.
for (var j:=0; j<5; j++) { log(5, "j is now: " + j); }
- first initializes the loop with creating j and setting it to 0 then repeats the (loop) statement block as long as j is less than 5, and increments j at the end of every iteration (_j++).
break
- exits a while, for or foreach loop.
continue
- starts the next iteration in a while, for or foreach loop.
foreach objectOrArray as value { do_something_with_value }
foreach objectOrArray as key,value { do_something_with_key_and_value }
- iterates through each field (when objectOrArray is an object) or each array element (when objectOrArray is an array) and assigns value and optionally key accordingly.
Return
return
- ends the current script or user defined function with null/undefined return value.
return value
- ends the current script returning value.
Catching Errors
try { statements; } catch { handling_statements }
- if any of statements generate a run time error, the handling_statements will be executed.
try { statements; } catch as error_var { handling_statements }
- if any of statements generate a run time error, the handling_statements will be executed and can use error_var to examine the error.
return is considered successful even if it returns an error
A return statement does not itself generate an error, even if it returns an error. I.e.
try { return error('error') } catch as e { ... } will not catch the 'error' with catch, but return it to the calling function.
throw(anything)
- generate a run time error with anything as error message. If anything is already an error value, the error value is re-thrown as-is.
User Defined Functions
function hello()
{
log('Hello World');
}
- Defines a globally available function named hello which logs the text 'hello world'.
global function sum(a,b)
{
var c = a+b
return c
}
- Defines a globally available function named sum with two arguments, which calculates and returns the sum in a local variable c (which exists privately for the function only during its execution). The global prefix is optional, but helps for clarity when local functions are in use as well (see below)
Visibility of variables in functions
In functions, the variables defined locally with var, the variables of the context from which the function is called (see local variables) and finally the global variables are visible. If a variable defined in the function has the same name as one of the calling context or a global variable, then the most local variable is used in expressions and assignments.
local function diff(a,b)
{
var c = a-b
return c
}
- Declares a function that is only visible/callable in the current context (such as: mainscript, device, trigger). This can be useful to avoid a function with no general use (e.g. one that is specific to a certain scripted device implementation) to be globally visible from other context, where calling it makes no sense or even would cause harm.
(Event) Handlers
A handler is a special construct provided by p44Script to easily react to asynchronous events of all kinds, such as the change of a sensor value, a keystroke, a web access, the termination of a thread, the reaching of a certain time of day or the expiration of an interval, and many more.
Basically, handlers are like functions that are automatically called when a certain condition is met (rather than getting called from other script code).
Handlers make implementing asychronous tasks - which are very common in automation, but are not so easy to implement in many standard scripting languages - quite straightforward and easy to understand.
var s = udpsocket("127.0.0.1", 4242, true, true);
on (s.message()) as msg
{
log('Message on UDP port 4242: '+string(msg))
}
- This first creates and opens a network socket listening for UDP packets on port 4242, and then defines a handler which triggers whenever a UDP packet arrives. (To send a UDP test packet on a unix command line, for example type:
echo -n "Test" | socat stdin "udp-sendto:127.0.0.1:4242")
Handling Timed Events
Combined with functions for timed triggering, handlers can perform tasks based on time:
on (after_time(12:00))
{
log('noon has passed ' + string(timeofday()-12:00) + ' seconds ago')
}
- Defines a event handler (piece of code that is executed when a specified condition is met).
- This handler is triggered by local time passing noon (12:00) and logs the number of seconds actually passed since noon - because when this handler is installed any time after 12:00, it will be run once immediately.
- By default, handlers are run when the trigger condition changes from false to true (but not when it changes from true to false).
on (every(0:15, 0))
{
log('another quarter of an hour has passed');
}
- Defines a event handler that is run every whole quarter of an hour.
Handling Value Changes via Event Sources
on (sensor1>20) toggling
{
log('sensor1 is ' + sensor1);
}
- Defines a event handler that triggers whenever the condition toggles from false to true or vice versa.
Note that sensor1 must be a event source for this to work. Contexts that have hardware inputs such as sensors
usually make these available as event sources (e.g. in P44-DSB Evaluators). For example, valuesource() or device.sensor() are event sources.
on (sensor2) changing
{
log('sensor2 is ' + sensor2)
}
- Defines a event handler that triggers whenever condition expressions re-evaluates to a different result as in the last evaluation.
on (sensor2) evaluating
{
log('sensor2 is ' + sensor2)
}
- Defines a event handler that triggers whenever the condition expression is evaluated, even if the result does not change.
Note: use this with care, depending on the event sources involved this can cause the handler to be run very often, which might cause performance problems.
on (sensor1+sensor2) changing as sensorsum
{
log('sensor1+sensor2 is ' + sensorsum)
}
- Defines a event handler that triggers whenever the sum of sensor1+sensor2 changes.
The as sensorsum part stores the result of the trigger expression into the variable sensorsum.
on (sensor1>22) stable 0:05 as sens
{
log('sensor1: stable for 5 minutes at > 22, currently: ' + sens)
}
- Defines a event handler that triggers when sensor1 remains over 22 for at least 5 minutes.
on (featureevent()) as event
{
log('received event ' + event)
}
- Defines a event handler that triggers whenever featureevent() triggers and stores the event in the variable event.
- Note that for event sources that deliver one-time events like featureevent() does, storing the actual trigger value in a variable using as is important.
Warning
As powerful as the handlers are, it is also possible to construct trigger conditions that lead to very frequent execution of the handler and thus potentially blocking or degrading the device's normal operation.
Concurrency (Threads)
p44script has a very convenient construct for creating concurrently running sequences of operations,
something that is often needed in automation. A concurrently running sequence of script statements is also called a thread
Note that event handlers as shown above also evaluate and run concurrently with other script activity.
concurrent {
while(true) { log('blink1'); delay(3) }
}
concurrent {
while(true) { log('blink2'); delay(2.7) }
}
delay(0:02); abort();
- run two asynchronously blinking sequences in parallel. After 2 minutes, both concurrent threads are stopped using the abort() function.
concurrent as blinker {
while(true) { log('blink'); delay(2) }
}
delay(0:02); abort(blinker)
- start a concurrent blinking sequence and save a reference to it as a variable named blinker.
- After two minutes, the variable can be used as argument to abort() to specifically stop a thread.
concurrent as task1 { delay(random(2,5)); log('task1 done') };
concurrent as task2 { delay(random(2,5)); log('task2 done') };
await(task1,task2)
log('one of both tasks done')
await(task1)
await(task2)
log('both tasks are done now')
- start two concurrent task with a random duration between 2 and 5 seconds.
- The await() function can be used to wait for completion of one of its arguments.
Using a separate await() call for each thread will complete when all tasks are done.
For complicated concurrency situations, also see lock() and and signal() for synchronizing threads.
concurrent passing x, y=2*a { log("x=%s, y=%s", x, y) }
- the passing keyword creates threadvar_s (variables with values private to the thread being started) and passes values (_x from a outside variable named x, y by assigning the expression 2*a) into the thread. This allows for using concurrent multiple times in quick succession while ensuring each started thread gets its own set of parameters.
Built-in Functions
p44Script has many built-in functions and methods (functions that are part of a object like a device, or a view etc.). Not all of them are available in any context. Therefore, this section has subsections, and some built-in functions/methods are listed further down along with the descriptions of their context (device, hardware etc.)
General Calculation Functions
These functions are available in every expression/calculation, and are real functions in the mathematical sense (no side effects, just providing the calculation results).
abs(a)
- absolute value of a.
annotation(something)
- Returns the annotation of something as a string. The annotation may describe the type or origin of a value more precisely, e.g. for null\ values the annotation can often give information why a value is null.
binary(hexstring [, spacesallowed])
- converts hexstring into a string (which can contain non-printable binary characters, including NUL) by exepcting 2 hex digits in hexstring for each output byte. Hex bytes might be separated by colons or dashes. If spacesallowed is set, bytes can also be separated by spaces, and bytes will also be considered complete if consisting of one hex digit only when preceeded and followed by a colon, dash or space. Also see hex().
bit(bitno, value)
bit(frombitno, tobitno, value, [, signed])
- the first form extracts a single bit as indicated by bitno (least significant bit has bitno==0) from value.
- The second form extracts a range of bits (between frombitno and tobitno) as a integer number. If signed is set, the bit range is treated as a signed integer (2's complement). Also see flipbit() and setbit() functions.
boolean(something)
- Interprets something as a boolean. If something is an empty string, undefined, null or the number 0, the result is false or 0, otherwise true or 1.
chr(byte)
- returns a string consisting of a single byte (value between 0 and 255). Note that not all values for byte create a valid (UTF8) string. However, this function is primarily indended to create binary byte strings - p44script strings can contain 0 bytes. Also see ord().
cos(angle)
- returns the cosine of angle (in degrees)
cyclic(x, a, b)
- return x with wraparound into range a..b (not including b, because it means the same thing as a).
dawn([epochtime])
- returns approximate time of dawn on the current day, or on the date specified by epochtime, but cannot directly trigger timed actions.
describe(something)
- Describes something as a string containing information on data type, internal name, annotation, etc. This function is useful for debugging purposes.
day([epochtime])
- returns current day of month, or the day-of-month component of epochtime, but cannot directly trigger timed actions.
dusk([epochtime])
- returns approximate time of dusk on the current day, or on the date specified by epochtime, but cannot directly trigger timed actions.
elements(_array_or_object_).
- If array_or_object is an array, elements returns the number of array elements. If array_or_object is an object, returns the number of fields (whose names can be obtained with array_or_object[numeric_index]). If array_or_object by type cannot have any elements accessible by index, undefined will be returned (but the number 0 if the object or array is currently empty).
epochtime()
epochtime(dayseconds [, yeardays, [, year]])
epochtime(hour, minute, second [, day [, month [, year]]])
- without arguments, the function returns unix epoch time (seconds since 1.1.1970 midnight UTC), but cannot directly trigger timed actions.
- With dayseconds argument only, the function returns epoch time of today with the time-of-day as represented by dayseconds.
- With yeardays, the function returns the epoch time represented by dayseconds/yeardays in the current year.
- With year the function returns the epoch time for the point in time corresponding to dayseconds/yeardays/year. Caution: Daylight saving time is not taken into account in this variant.
- With hour, minute, second and optionally day, month and year, the function returns the epoch time for the corresponding point in time, using current date/month/year if not specified.
epochdays()
- returns unix epoch time (days since 1.1.1970), with time-of-day as fractional part, but cannot directly trigger timed actions.
error(anything)
- creates a error value with anything as error message.
errorcode(errvalue)
- returns the numeric error code from errvalue.
errordomain(errvalue)
- returns the error domain string from errvalue.
errormessage(errvalue)
- returns the error message string from errvalue.
eval(string [, arg...])
- evaluate string as p44script script. The optional arg are available as variables named arg1, arg2 ... argN within the evaluation. The evaluation takes place in the current script's main context, and can access its variables, including global variables. However variables defined in the evaluation are local to the evaluation.
exp(n)
- raises e to the power of n (e being the Euler number 2.718281828459045). exp() is the inverse function of ln().
find(haystack, needle [, from [, caseinsensitive]])
- returns position of needle in haystack or null if not found. if from is specified, search starts at that position in haystack. if caseinsensitive is true, search is done case insensitively (simple ASCII-only case insensitivity).
flipbit(bitno, value)
flipbit(frombitno, tobitno, value)
- the first form returns value modified by flipping (inverting) a single bit as indicated by bitno (least significant bit has bitno==0).
- The second form returns value modified by flipping a range of bits (between frombitno and tobitno). Also see bit() and setbit() functions.
format(formatstring, value [, value...])
- formats value_s as string according to printf-like _formatstring (but note that formatstring only supports a subset of printf. In particular, no 'h', 'l' or 'll' length specifiers are allowed (nor needed). Recognized formatting chars are d,u,x,X for integer formatting, e,E,g,G,f for floating point, and s for strings.
formattime()
formattime(time)
formattime(formatstring)
formattime(time, formatstring)
- returns formatted time. Without arguments, formattime returns the current date and time like 2020-08-19 11:04:42.
- With only a numeric time argument, the specified time is formatted. When time is a time-of-day (between 0 and 24*60*60 seconds), only time is shown like 11:04:42 , otherwise time is treated as absolute unix epoch timestamp (see epochtime() function) and formatted as date+time by default.
- formatstring can be used to set a specific date and time format, using the formatting capabilities of the strftime() C standard function.
frac(a)
- fractional value of a (with same sign as a).
hex(string [, separator])
- returns the bytes contained in string (which might be a binary string containing non-printables and NUL characters) as a string of hexadecimal characters. If separator is specified, it will be used as separator between two-digit hex bytes (only first character of separator is used). Also see binary().
hour([epochtime])
- returns current hour, or the hour component of epochtime, but cannot directly trigger timed actions.
if(c, a, b)
- returns a if c evaluates to true, b otherwise.
ifvalid(a, b)
- returns a if a is a valid value (not null, error or non-data), otherwise return b.
ifok(a, b)
- returns a if accessing a does not return an error, otherwise return b.
int(a)
- integer value of a.
isvalid(a)
- returns true if a is a valid value (not null, error or non-data), false otherwise.
isok(a)
- returns true if accessing a does not return an error, false otherwise.
json(anything [, comments_allowed]).
- tries to interpret something as JSON. If something is a string, the string is treated as JSON text and parsed (rather than converted to a single JSON string). If a JSON syntax error occurs during parsing, json returns an appropriate error. If comments_allowed is set to true,
/* ... */ comments are allowed in the JSON text (which does not conform to the JSON specification, but is convenient).
This function is useful, for example, to make a JSON string returned by an API accessible as a structure.
jsonresource(jsonfile)
- Loads JSON from jsonfile. Without absolute path specification or special prefix, jsonfile is taken to be relative to the application's resource directory (which is usually /usr/share/application name). In JSON resource files,
/* ... */ comments are allowed (although this is not in accordance with the JSON specification).
-
The following special prefixes can be used:
_/tempfile : means that tempfile is to be used relative to the (volatile) temporary directory (usually /tmp).
+/resource : is equivalent to resource alone, so relative to the resource directory.
=/datafile : means that datafile is to be used relative to the (permanent) application data directory (usually /flash).
Note
To use paths or prefixes other than _/ for filename, the userlevel must be >=1 (default userlevel for production devices is 0).
lastarg(a1, a2, ... , aN)
- returns aN. This can be useful to execute side effects of other arguments first, before returning aN.
limited(x, a, b)
- returns min(max(x, a), b), i.e. x limited to values between and including a and b.
ln(n)
- returns the natural logarithm of n (logarithm to the base e = 2.718281828459045). l() is the inverse function of exp().
lowercase(s)
- returns (simple ASCII) lowercase version of string s.
macaddress()
- returns the MAC address of the wired network interface as a string of 12 hex digits (no separators between bytes).
maprange(x, a1, b1, a2, b2)
- maps x in the range of values a1..b1 linearly to the range of values a2..b2. For all values of x coming before a1 the result is a2, for all values of x following b1 the result is b2.
max(a, b)
- return the bigger value of a and b.
min(a, b)
- return the smaller value of a and b.
minute([epochtime])
- returns current minute, or the minute component of epochtime, but cannot directly trigger timed actions.
month([epochtime])
- returns current month (1..12), or the month component of epochtime, but cannot directly trigger timed actions.
nextversion()
- returns the next installable firmware version, when known (from automatic checking or a recent manual check for firmware upgrade). Otherwise an empty string is returned.
null(annotation)
- creates an annotated null value, that is a null value carrying some text that is shown in logs and when debugging - this annotation text has no function except for documentation. p44script itself often explains why something is null using annotations, the null() function allows script writers to do so as well.
number(anything)
- try to convert anything into a number, returns 0 if conversion fails.
ord(string)
- returns the byte (value between 0 and 255) stored in the beginning of string. Note that this first byte might not be a complete UTF8 character, but possibly only a part of it. However, this function is primarily indended to decode binary byte strings - p44script strings can contain 0 bytes. Also see chr().
productversion()
- returns the product's firmware version.
random(a, b)
random(a, b, step)
- returns a (floating point) pseudo-random value from a up to and including b. If step is specified, the result is equal to a plus an integer multiple of step. I.e. to get an integer between 1 and 7,
random(1,7,1) can be used. In this case, the randomness is evenly distributed among the possible outcomes (unlike, say, int(random(1,7)), which would have a vanishingly small probability for outcome 7 compared to 1..6). step does not have to be an integer; e.g. if quarters are required, random(1,7,0.25) can be used.
replace(haystack, needle, replacement [, occurrences]])
- returns haystack with occurrences of needle replaced by replacement, at most occurrences times (all occurrences will be replaced if occurrences is not specified or set to 0).
round(a [, p])
- round a to optionally specified precision p (1=integer=default, 0.5=halves, 100=hundreds, etc...).
second([epochtime])
- returns current second, or the second component of epochtime, but cannot directly trigger timed actions.
setbit(bitno, newbit, value)
setbit(frombitno, tobitno, newvalue, value)
- the first form returns value modified by setting a single bit as indicated by bitno (least significant bit has bitno==0) to the boolean value of newbit.
- The second form returns value modified by setting a range of bits (between frombitno and tobitno) to the integer number newvalue (using as many least significant bits from newvalue as is needed to fill the range). Also see flipbit() and bit() functions.
sin(angle)
- returns the sine of angle (in degrees)
string(anything)
- returns a string representation of anything. Always returns a descriptive string, even for null/undefined and error values.
strlen(string)
- returns length of string.
strrep(string, count)
- returns a string consisting of count times the string, concatenated.
substr(string, from [, count])
- returns string starting at from in string, limited to count characters if specified. If from is negative, start position is relative to the end of string.
sunrise([epochtime])
- returns approximate time of sunrise on the current day, or on the date specified by epochtime, but cannot directly trigger timed actions.
sunset([epochtime])
- returns approximate time of sunset on the current day, or on the date specified by epochtime, but cannot directly trigger timed actions.
timeofday([epochtime])
- returns current time-of-day in seconds since midnight, or seconds since midnight of epochtime, but cannot directly trigger timed actions.
uppercase(s)
- returns (simple ASCII) uppercase version of string s.
weekday([epochtime])
- returns current weekday (0..6), or the weekday of epochtime, but cannot directly trigger timed actions.
year([epochtime])
- returns current year, or the year component of epochtime, but cannot directly trigger timed actions.
yearday([epochtime])
- returns current date, or the date represented by epochtime, as day number in the year, but cannot directly trigger timed actions.
Functions for Timed Triggering
This is a special class of functions unique to p44script. These can be used in expressions that are meant to trigger an action at a specific point in time.
Please note that you must use these functions to test for time/date in evaluator or handler trigger conditions. Just writing something like timeofday()==12:30 will not work!
General functions returning time values such as sunrise() or dusk() are meant to be used as arguments to is_time() or after_time(), or to implement additional checks at the time when the expression is triggered by one of the following functions.
is_time(time)
- returns true when time of day is time (with 5 seconds tolerance) and triggers evaluation once per day when time is reached.
is_weekday(weekday1 [, weekday2, ...])
- returns true if today is any of the specified weekdayN arguments and triggers evaluation at the beginning of the specified days.
after_time(time)
- return true when time of day is time or later and triggers evaluation once per day when time is reached.
between_dates(date1, date2)
- true when current date is between date1 and date2 (inclusive) and triggers evaluation at beginning of date1 and at the end of date2.
initial()
- returns true if this is a
initial
run of a trigger expression, meaning after startup or expression changes.
every(interval [, syncoffset])
- returns true once every interval (specified in seconds) and triggers evaluation.
- Note: true is returned at first evaluation, or, if syncoffset is set, at next integer number of intervals calculated from beginning of the day + syncoffset.
-
So every(0:30,0:22) will trigger once every half hour, starting at 0:22, then 0:52, 1:22, ...
Attention - be careful with short intervals
Be careful with every() and short intervals, because running scripts very often can affect the performance of the device!
testlater(seconds, timedtest [, retrigger])
- returns undefined/null when called first, but schedules a re-evaluation after given seconds and return value of test then. If retrigger is true then, the re-evaluation will repeat in seconds interval (use with care!). Note that testlater() is available mostly for backwards compatibility with older setups, before the more general every() functions existed in p44script.
Script Programming Functions
Most of these functions are not functions in the mathematical sense, as they have side effects, which means they make something happen in the system such as accessing the network or device hardware, or general changes to the system's current state (such as changing the log level).
abort()
- aborts all concurrently running threads in the current scriptcontext, except the thread from where abort() is called.
abort(a [, abortresult [, self]])
- aborts the thread named a, i.e. the thread started with
concurrent as a {...}. If abortresult is not set to null, it will be used as the final result of the thread (returned e.g. by await()). If self is not set, and a is the current thread (i.e. the one from which abort() was called), then it will not be aborted, because that is usually not intended and hard to debug - if it is, self can be set.
await(a [,b,...] [, timeout])
- waits for one or multiple events to happen, for example a signal arriving (see signal()) or threads terminating, and returns the event's value.
if timeout is used, await will quit waiting after the specified time and return undefined.
breakpoint()
- When a script is being debugged in the p44script IDE, the debugger will stop when encountering the breakpoint() function. Without debugging enabled, breakpoint() does nothing. Note that usually it is easier to set breakpoints in the p44script IDE by clicking into the line number bar of the editor, so this functions is rarely needed.
delay(seconds)
- delays the script execution by seconds (floating point number; fractions of seconds are possible).
delayutil(dayseconds|epochtime)
- delay script execution until the time dayseconds (number of seconds since midnight, see timeofday() function) or epochtime (number of seconds since 1/1/1970 midnight UTC, see epochtime() function) is reached.
- Note that time literals also return seconds since midnight, so
delayutil(16:00) will wait until four o'clock.
dnssdbrowse(type [, hostname])
-
Searches for devices in the local network that make their services discoverable via the DNS-SD protocol (e.g. printers, but also many other devices, especially in the home automation area, including the P44-xx devices). With type a DNS-SD service type must be specified. For example, to find web interfaces, _http._tcp can be specified (see here for a complete list of service types). By specifying hostname, a specific device can be searched for by its hostname (in the form devicehostname.local).
As a result, dnssdbrowse returns an array which may be empty if no service of the specified type (and hostname, if applicable) was found. Otherwise, the array contains objects describing the service with the following fields:
- name: name of the service as a text description.
- hostname : hostname ending in
.local.
- hostaddress : the IP address on the LAN where the service can be reached.
- ipv6 : 1/true if hostaddress is an IPv6 address, 0/false otherwise.
- port : port number of the service
- interface : interface index of the network interface over which the service is reachable (only relevant for IPv6 if necessary).
- txts : object with the TXT records of the service as fields (can be empty if the service has no TXT records).
- url : This field a URL that can be used directly in a browser depending on the service type (composed of the above fields). For unknown service names http is assumed, which sometimes works for services with type other than http, but not always.
geturl(url [,timeout])
- returns response from GET request to (http or https) url, times out after timeout seconds if specified.
- If the url is prefixed with
!, SSL/certificate errors are ignored. For http(s) access with more options see httprequest().
httprequest(request [, data])
-
This is a generalized function that can be used instead of geturl(), puturl(), _posturl() when http requests with special headers, certificate checking, client certificate etc. are needed. All parameters are to be passed a request object:
- url: the complete URL. May contain a
! as the first character to prevent certificate checking for https connections.
- method : Optional, without specification
GET will be used.
- data : Data to send for PUT and POST, can also be passed directly as the second parameter of the function (especially necessary if it is a binary string). If data is a object value, the data is converted to JSON and sent with
Content_type: application/json on PUT and POST, otherwise with Content_type: text/html unless content type is explicitly specified in headers.
- formdata : optional boolean value. If this option is set to true and data is a object, the fields of the object will be sent as form fields with
Content_type: application/x-www-form-urlencoded.
- timeout : optional timeout in seconds.
- user : optional username for http auth (can also be passed as part of the URL).
- password : optional password for http auth (can also be passed as part of the URL).
- basicauth : optional mode for using http basic auth. By default, basic auth is only possible on https connections, and only if the server asks for it. With basicauth=onrequest basic auth is also allowed in non-SSL connections if the server asks for it. With basicauth=immediate, basic auth is sent with the first request (which may be necessary for simple IoT web servers, but offers very poor security without SSL). With basicauth=never, basic auth is not allowed at all, not even for SSL connections.
- headers : optional JSON object containing http headers to send as name/value pairs. If no
content-type is included, this header will be determined automatically from the supplied data (html or json).
- withmeta : optional boolean. If set to true, httprequest will return an object containing a status field with the http status code (success or error), a data field with the actual response (if any) and a headers field with all received headers as name/value pairs. Note that in this mode any request that leads to a http response will not be considered an error, regardless of the http status (whereas otherwise, only status 200..203 will be considered ok).
- clientcert : optional path to a client certificate to use.
- servercert : optional path to a root certificate or certificate directory to be used for checking the server certificate. If an empty string is specified, the server certificate will not be checked (which can also be archieved with a
! before the url, see above). By default, the server certificate is checked against the system's root certificates.
lock([entered])
-
Creates a Lock object, which can be used with its two methods .enter() and .leave() for synchronization of parallel running threads. If entered==true is specified, then the lock is already reserved for the calling thread when it is created. Normally one assigns a created lock to a variable: var l = lock(). The value of the lock is 0 if it is free, otherwise it specifies the nesting depth of the enter() calls of the thread that currently has reserved the lock.
Usually enter() is used in a conditional:
var lk = lock()
// ...
if (lk.enter(0:03)) {
// Sequentially executing code
// ...
lk.leave()
}
else {
log("3min timeout")
}
lk.enter([timeout])
- Waits until the lock lk is free. Without specifying timeout, the wait is indefinite. timeout can be 0 to only test the lock. The function returns true if the lock could be reserved for the calling thread. It returns false if the lock could not be reserved within the given timeout, or if the lock itself is deleted (for example with unset).
lk.leave()
-
Releases the lock lk. If other threads are waiting for the release, the thread that had called lk.enter() first gets access. leave() returns true if a release has actually been made with it. leave() from a thread that has not called enter() before returns false and does nothing.
Warning - beware of deadlocks
If locks are not used properly, it is easy to get into a situation where two threads have reserved one lock each, and are waiting for each other to release the other thread's lock, which may never happen. This is called deadlock and must be avoided. It is therefore recommended to use enter with timeout, so that a script application cannot block itself completely.
log([loglevel, ] logmessage [, value...])
- writes a message to the application log file. If loglevel is omitted, 5 (LOG_NOTICE) is used. If logmessage is followed by further arguments, logmessage is treated as a format string, as in the format() function (see there).
loglevel()
- returns the current log level.
loglevel(level [, deltatime [, symbols [, coloring]]])
- change the application's log level to level. If deltatime is set, timestamps will also show time difference to previous log entry in mS. If symbols is set, UTF-8 symbols will be used to differentiate log levels and separate context prefix from actual log message. If coloring is set, ANSI colors are used in the log output (suitable for terminal output, not browser). Each of the arguments can also be null in order not to change the corresponding value.
logleveloffset(offset)
- change the log level offset of the scriptcontext the script runs in to offset. This allows making part of an application more or less verbose in the log, selectively.
maxblocktime([time, [currentonly]])
-
return, or (with time argument, set) the maximum uninterrupted execution time for scripts (in seconds). The default is 0.05 seconds. When set with currentonly true, the setting only affects the current thread, otherwise this also sets the default for all future threads started from now on (but not already running threads, except for the calling thread).
High maxblocktime can severely affect device performance
setting maxblocktime too high will allow scripts to run uninterrupted for the specified time, without any other device function getting time to run, which might causing sluggish or blocked response including web interface. Recommended maxblocktime is under one second.
maxruntime([time|undefined])
- return, or (with time argument, set) the overall run time limit for the current thread (in seconds). The default is infinite (represented by undefined).
posturl(url [,timeout][,data])
- sends data (must be string or object/array) with POST to url, returns response, times out after timeout seconds if specified. If data is an object/array value, the data is converted to JSON and sent with
Content_type: application/json, otherwise with Content_type: application/x-www-form-urlencoded.
- If the url is prefixed with
!, SSL/certificate errors are ignored. For http(s) access with more options see httprequest().
puturl(url [,timeout][,data])
- sends data (must be string or object/array) with PUT to url, returns response, times out after timeout seconds if specified. If data is an object/array value, the data is sent with
Content_type: application/json, otherwise with Content_type: application/x-www-form-urlencoded.
- If the url is prefixed with
!, SSL/certificate errors are ignored. For http(s) access with more options see httprequest().
readfile(filename)
- reads the file filename as string.
-
Without absolute path specification or special prefix, filename is taken to be relative to the p44script data directory (a directory in permanent flash memory). The following special prefixes can be used:
_/tempfile : means that tempfile is to be used relative to the (volatile) p44script temporary directory.
+/resource : means that resource is to be used relative to the resource directory of the application
=/file : is equivalent to file alone, so relative to the p44script data directory
Note
To use paths or prefixes other than _/ for filename, the userlevel must be >=1 (default userlevel for production devices is 0).
restartapp(["reboot"|"shutdown"|"upgrade"])
- restarts the application (on P44-xx devices this is the vdcd). Without arguments only the application is restarted, not the whole device (this usually takes only a few seconds, but may take longer if there are many DALI devices connected). This "small" restart is especially useful when developing/testing more complex scripts.
-
With "reboot" as parameter the device is completely restarted, with "shutdown" it is shut down and stopped, so that it only starts again when it is disconnected from the power supply and reconnected (be careful with this if you are not on site!). With "upgrade" an upgrade to the latest available firmware is triggered (which triggers a reboot in any case, even if no new firmware is available).
Caution
Using restartapp() in scripts that are executed automatically (e.g. the mainscript) may cause the device to enter a reboot loop that can only be interrupted by a factory reset. So please consider carefully whether the conditions that lead to the execution of restartapp() are correct and do not trigger again immediately after each restart!
shellquote(argument)
- returns argument interpreted as string and single quote enclosed such that it safely works as a single shell argument (even if argument contains single quotes itself) and no shell variable expansion occurs.
signal()
- creates a "signal" object which can be assigned to a (possibly global) variable (signal_var below). Threads can wait for the arrival of the signal with await(), or the signal variable can be used as a trigger condition in on()\ handlers. The signal object has a send() method that can be used to trigger (send) a signal, see below.
signal_var.send()
- sends a signal with the signal value = true (numeric 1)
signal_var.send(signalvalue)
- sends a signal with signalvalue. signalvalue can be any value, but remember that simple
on(condition) {} handlers only trigger when condition evaluates to a "trueish" value. To catch all values, including null, undefined, 0, false, on(condition) evaluating {} can be used. Waiting for a signal with await() returns on any signal value, including all "falsish" ones.
system(commandline)
-
executes commandline using the platform's shell and returns the output as string.
Note
The system() function is only available when userlevel is >=2 (default userlevel for production devices is 0)
Warning
As the system() function can call any OS-level command, it can seriously damage the firmware up to bricking the device.
That's why it is not enabled by default. If you have a DIY P44-DSB-X, you can set the userlevel to >=2 yourself to use it,
but be careful!
udpsocket(host, port, receive, nonlocal, broadcast)
- returns a UDP socket configured to send packets to host:port. Use .send(string) method to send data
- If receive is true, the socket can also receive UDP packets (via its .message() method, which can be used in on() statements as trigger.
- If nonlocal is true, the socket can also receive UDP packets originating from other hosts than just localhost (which is the default).
- If broadcast is true, the socket can send and receive broadcast packets
- Usually the return value of this function is assigned to a variable:
var udpsocket_var = udpsocket(...) to be able to call the methods described below.
udpsocket_var.message()
- is a event source which returns UDP messages received on the socket. It can be used in on() statements as trigger condition and can also be await()-ed.
udpsocket_var.send(string)
- sends string as UDP packet.
undeclare()
- deletes all function and handler definitions that are not part of a stored script, but were made in an ad-hoc way,
for example from a interactive script command line (a REPL = Read-Execute-Print-Loop).
Note that functions and handlers defined in a script text stored in the application (such as trigger actions, scene scripts, etc.) remain tied to these script texts,
i.e. are updated (or removed) according to edits in the script text, and will not be removed by undeclare().
urlencode(text [, x-www-form-urlencoded])
- Encodes the text for use in a URL or, if x-www-form-urlencoded is true, for sending form fields in POST data.
websocket(url [, protocol [,pinginterval]])
- Creates a websocket connection to the given url with the protocol ("Sec-WebSocket-Protocol" header) protocol and the given pinginterval.
- Usually one assigns the return value of this function to a variable:
var websocket_var = websocket(...) to be able to call the methods described further below.
websocket(configobj)
-
In this variant all parameters are passed in configobj. This allows for more advanced options. The following fields are supported:
- url: the websocket URL (ws: or wss:)
- protocol: the subprotocol ("Sec-WebSocket-Protocol"-header)
- pinginterval: the ping interval
- headers : optional JSON object containing http headers to send as name/value pairs.
-
Usually the return value of this function is assigned to a variable: var websocket_var = websocket(...) to call the methods described below.
websocket_var.message()
- is a event source which returns websocket messages received on the socket. It can be used in on() statements as trigger condition and can also be await()-ed.
websocket_var.send(message [, opcode])
- sends message as a websocket message. If opcode is not specified, the message will be sent as "text" (opcode 1).
websocket_var.close([closecode [, reason]])
- closes the websocket with the close-code "Normal" (1000), or the given closecode. If specified, reason is included in the close-message.
writefile(filename, something [, append])
- converts something to a string, and writes the result as file filename. If something == null, filename is deleted. If append is set to true, something is appended to the end of the file if it already exists, otherwise an already existing file is overwritten.
-
Without absolute path specification or special prefix, filename is taken to be relative to the p44script data directory (a directory in permanent flash memory). The following special prefixes can be used:
_/tempfile : means that tempfile is to be used relative to the (volatile) p44script temporary directory.
+/resource : means that resource is to be used relative to the resource directory of the application
=/file : is equivalent to file alone, so relative to the p44script data directory
Note
To use paths or prefixes other than _/ for filename, the userlevel must be >=2 (default userlevel for production devices is 0).
Controlling Device/Product Specific Subsystems
Note - Product specific features
The features described in the following sections depend on the device type, especially the control of external hardware via GPIO connectors, which needs specially equipped device variants (e.g. the LED controller P44-LC-LED, or the automation controller P44-AC-DCM), or then DIY setups like the P44-DSB-X image on Raspberry Pi.
P44-DSB/P44-LC: Access to Devices and API
Note: the following functions are available in device level scripts (such as scene scripts).
But basically, these functions are members of the device object or of one of its members. The device object can also be obtained from global scripts using the device function, see below. This allows statements like: device('mydevicename').output.channel('brightness',75)
output
- Represents the output of a device (for devices without output, this is undefined).
output.applychannels([force [, transitionTimeOverride]])
- apply changes to channels made with dimchannel and channel. If force is true, even unchanged channels will be re-applied to the hardware. If transitionTimeOverride is set, transition times of all changing channels will be overridden with the specified value. Otherwise, the transition times as loaded from a scene with loadscene or individually set with channel apply.
output.syncchannels()
- force reading back actual channel values from hardware.
output.channel(channelid)
- returns the current value of channelid ('brightness', 'hue', 'saturation', 'colortemp', 'hPos' - note: channelIDs are case sensitive! You can also specify 0 for accessing default channel of the respective device)
- Note that channels have subfields named .valid (true if the channel is know in sync with the hardware), .age (seconds since last change), and .oplevel (a value between 0..100 indicating the overall "health" level of the device the channel belongs to, which includes radio reception, battery level etc.). A channel is an event source and can be used in on() statements as trigger condition and can also be await()-ed.
output.channel(channelid, value[, transition_time])
- set the value of channelid to value, with optional transition_time in seconds.
- Note that the channel value change is not automatically applied to the hardware; you need to call applychannels() for that. Also note that channelids are case sensitive! You can specify 0 for accessing default channel of the respective device.
output.dimchannel(channelid, valuechange, transition_time)
- change the value of channelid by valuechange, with optional transition_time in seconds. Note that channelids are case sensitive! You can also specify 0 for accessing default channel of the respective device.
output.movechannel(channelid, direction [, time_per_unit])
- starts moving the value of channelid in the direction indicated by the sign of direction or stops movement when direction is 0. When optional time_per_unit in seconds is set, it determines speed by setting the time spent per change of 1 unit of the channel value. If time_per_unit is not specified or set to 0, the channel's default dimming speed is used instead.
- Note that the channel movement is not automatically started; you need to call applychannels() for that. Also note that channelids are case sensitive! You can specify 0 for accessing default channel of the respective device.
output.loadscene(sceneIdOrNo [, transitionTimeOverride])
- loads the channels of the output with the values stored in the scene sceneIdOrNo. The scene is determined by its number or preset name (e.g. 'bell 1' or 'preset 2'). If transitionTimeOverride is specified, the transition times of all channels are set to this value, even if the scene defines other values.
Please note that the loaded new channel values are not automatically applied to the hardware; applychannels() must be called for this. loadscene() can be used e.g. to load a scene but still adjust it with channel() before applying it to the outputs.
output.runactions(sceneIdOrNo)
- runs the scene actions (e.g. blinking, or starting a scene script) of scene sceneIdOrNo. The scene is determined by its number or preset name (e.g. 'bell 1' or 'preset 2').
output.stopactions()
- stops all running scene actions (scene scripts, blinking, etc.) and all running channel transitions.
sensor('id_or_index')
- returns the current value of a sensor input. id_or_index can be either the index of the sensor (starting at 0), or the text id (a string like 'temperature' or 'humidity', depending on what the device actually provides)
- Note that sensors have subfields named .valid (true if the sensor has an actual value), .age (seconds since last update), and .oplevel (a value between 0..100 indicating the overall "health" level of the sensor, which includes radio reception, battery level etc.). A sensor is an event source and can be used in on() statements as trigger condition and can also be await()-ed.
input('id_or_index')
- returns the current value of a binary input. id_or_index can be either the index of the binary input (starting at 0), or the text id (a string like 'rain' or 'window_handle', depending on what the device actually provides). Input values are usually 0 or 1, but special inputs like window handles might have more states (2,3...).
- Note that inputs have subfields named .valid (true if the input state is known), .age (seconds since last update), and .oplevel (a value between 0..100 indicating the overall "health" level of the input, which includes radio reception, battery level etc.). A input is an event source and can be used in on() statements as trigger condition and can also be await()-ed.
Global Level
Note
these global functions allow accessing specific devices in the P44-DSB/P44-LC directly, or indirectly by using the vDC API. These might be needed for advanced custom applications, such as complex effect setups requiring coordinated control of multiple devices, usually from a global main script. For scripting related to a single device, using device-level scripts such as the scene script is preferable.
Please be careful accessing devices and API directly.
device('devicename')
device('dSUID')
- access a device by devicename or dSUID. Note that while using names is more convenient, scripts might break when users rename devices. So using dSUID is recommended for scripts that are meant to remain installed and working for a long time.
valuesource('valuesource_id')
- find a value source (source of values that can trigger on(xxx) expressions or evaluator conditions) by its internal id. Note that ususally, it is better to access these values using device(x).sensor(y).
vdcapi(json_request)
- issues a vDC API method call or a notification. Returns the method's response or just an empty result for a notification.
webrequest()
- Is an event source which returns JSON requests sent to the scriptapi endpoint of the JSON API. webrequest can be used, for example, with
on(webrequest()) as request { ... } to implement API commands in scripts. The return value of webrequest() has the method answer() to answer the request. The whole mechanism can be used when implementing custom special web pages besides the standard web interface.
request.answer(json_or_error)
-
Replies to a web request (the request variable in the example above) with a JSON response or error. Typically, a response is sent as part of an on() handler, with a construct such as:
on (webrequest()) as request {
// execute request
// ...
request.answer({ "status": "all ok"});
}
webrequest must be answered!
If an on(webrequest()) as request { ... } is installed, it must be ensured that the handler code really answers the request with answer() in every case. Otherwise, the requesting web client will hang until it times out.
Built with MkDocs.