Phi: variables in more detail

Here are the available variables for Phi scripts.

In Assetwolf, the term "node" refers to an asset, or to a data pool. 

For assets

The thisRow object will contain the row from the database that's currently being processed by the data-processor.

Variable Meaning
thisRow.value An array containing the incoming data or assumed value*
thisRow.actual An array containing the stated incoming data
thisRow.lastKnown An array containing all of the entries from thisRow.value that were assumed
thisRow.lastKnownAt An array containing the timestamps for all of the entries in thisRow.lastKnown
prevRow.actual An array containing the incoming data from the previous row
prevRow.lastKnown An array containing every entry from prevRow.value that was assumed
prevRow.lastKnownAt An array containing the timestamps for all of the entries in prevRow.value


* The "value" array is the simple way to get to the latest value of a field, and does not discern between known and assumed values. (Remember that Assetwolf supports rows of data coming from assets in which fields may be missing. When the asset sends data but a field on its schema is missing, the last-known value is inserted into the database, with a flag to say it was "assumed".)


#If you just want the most recent value for the light level, and don't care if it was assumed
lightLevel = thisRow.value.lightlevel

#If you want more details about when the value for the light level was received
if (thisRow.actual.lightlevel is not null) {
	lightLevel = thisRow.actual.lightlevel
	lightLevelTS = thisRow.timestamp
	lightLevelWasAssumed = false
} else {
	lightLevel = thisRow.lastKnown.lightlevel
	lightLevelTS = thisRow.lastKnownAt.lightlevel
	lightLevelWasAssumed = false

For data pools

Data pools aggregate data for multiple assets that they contain, or other data pools.

Assetwolf processes each data pool when all of its child data pools have calculated data, or when any one of its source data pools has calculated data twice.

When this occurs, the Phi script may contain the following source variables.

Variable Meaning The total number of sources
source.numKnown The number of sources that are transmitting data
source.numAssumed The number of sources that did not transmit data this time
source.values An array of arrays containing all of the data from the sources. Note this will include assumed data if one or more of the sources missed a transmission



#Get the highest/lowest/average/total values
maxLightLevel = max(source.values.lightlevel)
minLightLevel = min(source.values.lightlevel)
totalLightLevel = sum(source.values.lightlevel)
averageLightLevel = mean(source.values.lightlevel)

//N.b. the sources are arrays of data, so you can loop through them
maxLightLevel = 0
minLightLevel = Infinity
totalLightLevel = 0
for (lightLevel in source.values.lightlevel) {
	if (maxLightLevel < lightLevel) {
		maxLightLevel = lightLevel
	if (minLightLevel > lightLevel) {
		minLightLevel = lightLevel
	totalLightLevel += lightLevel
averageLightLevel = totalLightLevel / count(source.values.lightlevel)

For both assets and data pools

Both asset and data pool schemas have the following variables.

Variable Meaning
metadata An array containing the asset or data pool's metadata
schema An array containing the schema's metadata
thisRow.timestamp The timestamp of the data being processed. All timestamps are in milliseconds since the epoch time; i.e. the number of milliseconds that have past since the 1st of January 1970 UTC.
prevRow.timestamp The timestamp of the previous data received
prevRow.value An array containing all of the incoming data/assumed values/calculated values from the previous row


activationsThisTime = thisRow.value.activations - prevRow.value.activations
activationsPerSecond = activationsThisTime * 1000 / (thisRow.timestamp - prevRow.timestamp)


There are several functions that refer to nodes in any hierarchy:

Function Use
getMetadata(name[, nodeId]) This function gets the value of the metadata field in name. Defaults to that of the current node, but gets that of nodeId if it is specified. (This function gets the value of name from the node itself, not from a parent node).
getInheritedMetadata(name[, nodeId]) Gets the value of the metadata field in name that is inherited from a parent node (or any higher level parent). Defaults to the current node (data pool or asset), but gets that of nodeId if specified. Use this rather than getMetadata in situations where name may be set on the node itself or inherited from a parent.
setValue(key, value) Sets the value of a calculated field. The field needs to be defined as such in the schema for that node. It won't work on any other type of field (i.e. you can't use it to change the value of incoming data).
getHistoricValue(key, timestamp)

Retrieves a historic value.

Given a key and a timestamp, and the function will tell you what that value was at that time. (The timestamp does not need to be an exact match to a datapoint; you'll receive an assumed value if it does not perfectly match.)

As a shortcut you can also enter a description from the above function, e.g.: getHistoricValue('light_level', '2 days ago').

getTimestamp(description[, timestamp])

Given a description such as:

Note that any times you specify (e.g. 3pm) will be according to the default timezone set in the site settings, and not the user's time zone.

If you type something relative then you can specify another timestamp to match against - otherwise if not specified it will default to thisRow.timestamp.

print(var1, var2, ...)

This can be used while testing your Phi code to check the values of variables and add them to the debug-output.

This function only functions while testing your code; the data-processor ignores it.



activationsThisWeek = thisRow.value.activations - getHistoricValue('activations', '1 week ago')
setValue('activations_this_week', activationsSinceLastWeek)


Advanced usage

Remember that Phi is based on a subset of the Twig language, so see for more information about Twig syntax.

Any basic expression, filter or operator from Twig will also work in Phi, for example:

n = -12
print(n|abs)		#12

print(1 is odd)		#true
print(1 is even)	#false

colour = 'Red'
t = "my car is #{colour}"

print(t)			#"my car is Red"
print(t|lower)		#"my car is red"
print(t|upper)		#"MY CAR IS RED"
print(t|capitalize)	#"My car is red"
print(t|title)		#"My Car Is Red"

r = t|replace({car: 'van'})
print(r)			#"my van is Red"

x = 1
y = 2 t = "#{x} plus #{y} is #{x + y}" print(t) #"1 plus 2 is 3" n = 1.234e7 print(n|number_format) #"12,340,000" numbers = [4, 5, 6] print(numbers|join(',')) #"4,5,6" fruit = "apple,banana,cherry" print(fruit|split(',')) #["apple", "banana", "cherry"] t = ' Hello world ' print(t starts with 'H') #false print(t ends with 'd') #false t = t|trim print(t) #"Hello world" print(t starts with 'H') #true print(t ends with 'd') #true print(t matches '/hello/') #0 print(t matches '/Hello/') #1 print(t matches '/hello/i') #1 print('Hello' in t) #true print('Hi' in t) #false

You can end each line with a semicolon, but it's not necessary.

Note that Twig's environment functions such as constant(), include(), parent() and source() do not work in Phi.