Custom event detectors?
-
Hey hey, I have an implementation question, kind of a "what's the best way to do this" question.
What I would like to do is look at a point, take the average over the last hour, every hour, and compare that to the average value of the same hour over the last five days. So for example, at 6am calculate the average value of the last hour and compare that to the last 5 days of 5-6am average values.
I have an idea on how I could possibly do that but it would require another point to keep track of the last five days average. I was curious if there was a way to create an event detector to do that for me? That way it's really easy to attach that detector to each one of my points.
-
Hi psysak,
Defining something like an event detector takes a module, currently, and the UI doesn't support the custom event detectors. Here's the git issue on that: https://github.com/infiniteautomation/ma-core-public/issues/742, no timeline as few people have asked about getting a custom event detector to function like the event detectors.
Of course, the reason people haven't needed that is that scripts can do most anything...
//Apply the described checking to all the context points of the script... var now = new Date(); //execute on cron 0 0 6 * * ?, zero out now's milliseconds, seconds, minutes, and set hour if desired for(var varName in CONTEXT_POINTS) { //maybe the alarm output point is also in the context.... //if( varName.endsWith("output") ) continue; //ignore context points with variable names ending in output var historyList = []; for(var j = 5; j >= 0; j-=1) { historyList.push( this[varName].getStats(now.getTime()-j*86400000-3600000, now.getTime()-j*86400000).average ); } //print(historyList) //Okay, now check the history list for the condition and set out values accordingly. //if( historyIsSketchy(historyList) ) this[varName + "_output"].set("Open faucet?"); //historyIsSketchy function not supplied }
-
Ohhh.... Is what you wrote there a single scripting source script? That CONTEXT_POINTS set off a bit of a lightbulb cause I could just put all my points into one script couldn't I? I create a separate point with a script associated as follows, however my solution would require another point for each point I want to monitor... This does however have the upside of allowing me to trend the hourly difference
// This script is used to calculate a running average of the previous hour over // a five day period. var previousHours = []; current = CONTEXT.getTimestamp(); var d = new Date(); var j = 1; for(i = 1; i <= 7; i++) { date = current - (86400000 * i); d.setTime(date); if(d.getDay() > 0 && d.getDay() < 6 && j <= 5){ previousHours[j] = pv.pointValueBefore(date).value - pv.pointValueBefore(date - 3600000).value; j++; } } average = (previousHours[1] + previousHours[2] + previousHours[3] + previousHours[4] + previousHours[5]) / 5; result = 100 * ((pv.value - pv.ago(HOUR, 1)) - average) / average; //This point is an alpha for now until this script is proven accurate return result + ", " + (pv.value - pv.pointValueAfter(pv.time - 3600000).value) + ", " + average;
But with yours I could just run through all my points in a single script. Could I trigger a binary event detector lets say on the parent point from the script? So I would have my points which I want to test, I add a binary event detectors to each, write a single script with all points as part of the context and then trigger the event on the point which violates my setpoint. Is that doable?
-
Ohhh.... Is what you wrote there a single scripting source script?
Not necessarily. I didn't do anything there that wouldn't work in any of Mango's script environments (well, using a cron pattern limits it to scripting or meta). I did think of it as being a scripting data source, though. CONTEXT_POINTS is a map of varName to their DataPointRT (which is different than the point's script wrapper, so
this[varName] !== CONTEXT_POINTS[varName]
)I create a separate point with a script associated as follows, however my solution would require another point for each point I want to monitor...
If you're not familiar with Alphanumeric points' regex state detector, you may find that suiting to setting error messages with additional information into a single point and emailing that. You would need to set it back to a non-error state to get the event to raise again, but that's simple enough.
If you want historical trending, I would use a meta point for any point you wished to do this for, executing on the same cron and storing the last hours average, something like...
var thisAverage = p.last(HOUR).average; var myHistory = my.last(5); //list of PointValueTime objects var historyList = []; for( var j = 0; j < 5; j+=1 ) { historyList.push( myHistory[j].doubleValue ); } historyList.push(thisAverage); var historyScore = historyIsSketchy( historyList ); if( historyScore > 0 ) { //Not null, some string returned, whatever you want to pass to the output point alphanumericRegexStateDetectedContextPoint.set("Badness: " + my.getDataPointWrapper().getExtendedName() + " had a history score of " + historyScore); alphanumericRegexStateDetectedContextPoint.set(""); } return thisAverage;
The small blemish being if two meta points interleaved in setting the regex state detecting point to the detected state before reseting it to the base state, one of those events wouldn't be raised. There are certainly ways to solve that if need be.
While it may be possible to put event detectors directly on the points you wish to average and then force them somehow through a script that is doing the detection on its context points, that would definitely be hacky. Do you need the event detectors on the points, or to record these events against each point?
Edit: And for anyone who likes the simplicity of CONTEXT_POINTS on a scripting data source (where you would only have to add a point to the context to get that behavior), it may be excessive (you could just generate them once and be done, too) but you could create a script to create these meta points for any points in the context (probably want to check if they already exist first!)