Data Management
Calculations
Calculation examples
sampled calculations add 2 variables tengo return a value + b value select variable based on condition tengo if a value > 100 0 { return b value } else if a value < 100 0 { return c value } return a value calculate enthalpy if97 steam functions and units tengo // get input values for temperature and pressure from input references temperaturecelsius = a value // assuming a is an alias for temperature input in celsius pressurebar = b value // assuming b is an alias for pressure input in bar // convert temperature from celsius to kelvin temperature = units convert(temperaturecelsius, "c", "k") // convert pressure from bar to pascal pascal = units find("pa") pressure = units convert(pressurebar, "bar", pascal) // calculate the specific enthalpy of steam using the if97 specificenthalpy function enthalpy = if97 specificenthalpy(temperature, pressure) // save the enthalpy value in local memory (optional) local set("enthalpy", units float(enthalpy)) // return the calculated specific enthalpy return enthalpy calculate flow from current mass tengo mass = float( a value) // assuming a is an alias for mass input in kg seconds = context intervalms / 1000 0 // convert from milliseconds interval to seconds return mass / seconds // flow rate in kg/s raw calculations map number to string tengo if a value == 1 0 { return "step a" } else if a value == 2 0 { return "step b" } return "invalid" map step numbers to string setting status in script tengo // build map of step numbers stepnumbers = { "100" "running", "101" "filling", "102" "running", "103" "emptying", "104" "bottling", "105" "packaging", "201" "cleaning", "300" "planned stop", "400" "unplanned stop" } // look up current step in map step = stepnumbers\[ category value] / values not in map are considered bad data > set status other than good to discard data for downstream processing / if is equal(step, undefined) { 	set status("badunknownstepnumber") 	step = 0 } return step extract value from string using regex tengo result = text re find("\\\\\\\d+\\\\\\\\ ?\\\\\\\d ", a value) // eg a = "some 2344324 34 value" if result != undefined && len(result) > 0 { found = result\[0]\[0] text return float(found) } elapsed time since previous value in seconds set tag in script tengo previous = context previousinput a if previous { // subtract timestamps difference = times sub( a timestamp, previous timestamp) // return result in seconds default times sub result is in nanoseconds difference seconds = times duration seconds(difference) // add a time series tag to the result indicating if the calculated difference is within the expected range if difference seconds > 10 || difference seconds < 1 { set tag("range check", "out of bounds") } else { set tag("range check", "ok") } 	return difference seconds } return 0 use tags in calculation tengo if is equal( a tags range check, "ok") { return a value } incremental counter local context library tengo threshold = 100 previous = float(local get("previous"),0 0) result = previous + a value if result >= threshold { 	local set("previous", 0 0) 	return 0 0 } local set("previous",result) return result incremental counter calculation context tengo threshold = 100 previous = float(context previousresult value, 0 0) result = previous + a value if result >= threshold { 	return 0 0 } return result incremental counter with 1 output point per day tengo previous = float(local get("previous"),0 0) result = previous + a value // calculate hour in the day hour = times hour(context timestamp) previous hour = times hour(context previoustimestamp) / only when current and previous values are on different sides of 1pm, the value is returned and the counter reset since the calculation is raw, we cannot be sure that the input has a value at exactly 1pm if that would be the case, we could also use times time minute and times time second to match 1pm exactly / if (hour >= 13 && previous hour <= 13) { local set("previous", 0 0) 	return result } // on all other timestamps, save the result but do not return it local set("previous",result) // an empty return will not write a point to the time series database return current value from incremental counter with resets tengo / previous result is undefined at first this should be prevented from impacting the result / if is equal(context previousresult, undefined) { return 0 0 } current = float( a value) previous = float(context previousresult value) / if current value is lower than previous, counter was reset we assume reset to zero and output current value as difference with zero / if current < previous { 	return current } // write difference with previous value return current previous convert ascii number to character the library function fmt sprintf is an alias for the builtin function format the two scripts below are therefore identical tengo return format("%c", int( a value)) tengo return fmt sprintf("%c", int( a value)) integer byte conversions convert 16 bit integer to byte, then convert each separate byte back to an 8 bit integer using a function and sum the result together tengo // function to convert bytes to 8 bit integers bytetoint = func(value) { 	return text parse int(value, 2, 8) } // convert input integer to bytes bts = fmt sprintf("%016b", int( a value)) // convert first and last 8 bits to separate integers first = bytetoint(bts\[ 8]) last = bytetoint(bts\[8 ]) // sum the resulting numbers return first + last calculate flow efficiency based on asset metadata tengo // get max flow from asset metadata maxflow = factry get input asset metadata(" a", "maxflow") return a value / maxflow // assuming a is an alias for flow input and maxflow is in the same unit simulated calculations generate random float between 0 and 1 tengo return rand float() write value based on current time for live calculations, times now() provides the same timestamp as context timestamp however, for recalculations this is no longer the case tengo // calculate hour in the day hour = times hour(context timestamp) // only return 1 between 1pm and 2pm if (hour >= 13 && hour <= 14) { return 1 } return 0 write value based on current time with timezones tengo // localize timestamp in europe/brussels time zone timestamp = times to location(context timestamp, "europe/brussels") // calculate day of the month and hour in the day day = time weekday(timestamp) hour = times hour(context timestamp) // only return 1 between 1pm and 2pm on a monday if day == 1 && (hour >= 13 && hour <= 14) { return 1 } return 0 write formatted timestamp tengo // localize timestamp in europe/brussels time zone timestamp = times to location(context timestamp, "europe/brussels") // format timestamp following the rfc3339 convention return times time format(timestamp, times format rfc3339)